Fix for FileState.Create constraint violation in StatusAgent.cs
authorpkanavos <pkanavos@gmail.com>
Thu, 26 Apr 2012 18:50:56 +0000 (21:50 +0300)
committerpkanavos <pkanavos@gmail.com>
Thu, 26 Apr 2012 18:50:56 +0000 (21:50 +0300)
Uploader.cs modified to check if it is possible to upload a new shared file before actually uploading
CloudFilesClient.CanUpload added that checks whether a file can be uploaded in the parent folder of a target object

Closes #2352

trunk/Pithos.Core/Agents/StatusAgent.cs
trunk/Pithos.Core/Agents/Uploader.cs
trunk/Pithos.Network.Test/ObjectInfoTest.cs
trunk/Pithos.Network/CloudFilesClient.cs
trunk/Pithos.Network/RestClient.cs

index 9ec5d00..94bdbeb 100644 (file)
@@ -350,7 +350,7 @@ namespace Pithos.Core.Agents
                         {
                             var createdState = FileState.CreateFor(FileInfoExtensions.FromPath(path));
                             createdState.FileStatus = status;
-                            _persistenceAgent.Post(createdState.Create);
+                            createdState.Create();
                         }
                         return affected;
                     }
@@ -390,7 +390,7 @@ namespace Pithos.Core.Agents
                             var createdState=FileState.CreateFor(FileInfoExtensions.FromPath(absolutePath));
                             createdState.FileStatus = fileStatus;
                             createdState.OverlayStatus = overlayStatus;
-                            _persistenceAgent.Post(createdState.Create);  
+                            createdState.Create();  
                         }
                         return affected;
                     }
index 8239341..ee6bfb2 100644 (file)
@@ -83,14 +83,28 @@ namespace Pithos.Core.Agents
                         {
 
                             var client = new CloudFilesClient(accountInfo);
+
                             //Even if GetObjectInfo times out, we can proceed with the upload            
                             var cloudInfo = client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name);
 
-                            //If this is a read-only file, do not upload changes
-                            if (!cloudInfo.IsWritable(action.AccountInfo.UserName))
-                                return;
+                            //If this a shared file
+                            if (!cloudFile.Account.Equals(action.AccountInfo.UserName,StringComparison.InvariantCultureIgnoreCase))
+                            {
+                                //If this is a read-only file, do not upload changes
+                                if (!cloudInfo.IsWritable(action.AccountInfo.UserName))
+                                {
+                                    MakeFileReadOnly(fullFileName);
+                                    return;
+                                }
 
-                                //TODO: If the object does not exist, check that we can upload to the folder
+                                //If the file is new, can we upload it?
+                                if ( !cloudInfo.Exists && !client.CanUpload(account, cloudFile))
+                                {
+                                    MakeFileReadOnly(fullFileName);
+                                    return;
+                                }
+
+                            }
 
                             if (fileInfo is DirectoryInfo)
                             {
@@ -143,7 +157,7 @@ namespace Pithos.Core.Agents
                             if (response.StatusCode == HttpStatusCode.Forbidden)
                             {
                                 StatusKeeper.SetFileState(fileInfo.FullName, FileStatus.Forbidden, FileOverlayStatus.Conflict, "Forbidden");
-                                
+                                MakeFileReadOnly(fullFileName);
                             }
                             else
                                 //In any other case, propagate the error
@@ -177,6 +191,15 @@ namespace Pithos.Core.Agents
             }
         }
 
+        private static void MakeFileReadOnly(string fullFileName)
+        {
+            var attributes = File.GetAttributes(fullFileName);
+            //Do not make any modifications if not necessary
+            if (attributes.HasFlag(FileAttributes.ReadOnly))
+                return;
+            File.SetAttributes(fullFileName, attributes | FileAttributes.ReadOnly);
+        }
+
         private static AccountInfo GetSharerAccount(string relativePath, AccountInfo accountInfo)
         {
             var parts = relativePath.Split('\\');
index 72a0253..61f5cd9 100644 (file)
@@ -18,12 +18,12 @@ namespace Pithos.Network.Test
 
             var info1 = new ObjectInfo {Account = "pkanavos", Container = "pithos", Name = "somefolder/file1.txt"};
             var path1=info1.RelativeUrlToFilePath("PKANAVOS");
-            Assert.AreEqual(@"somefolder\file1.txt",path1);
+            Assert.AreEqual(@"pithos\somefolder\file1.txt",path1);
             var path2 = info1.RelativeUrlToFilePath("user1");
-            Assert.AreEqual(@"others\pkanavos\somefolder\file1.txt", path2);
+            Assert.AreEqual(@"others-shared\pkanavos\pithos\somefolder\file1.txt", path2);
             var info3 = new ObjectInfo { Account = "pkanavos", Name = "somefolder/file1.txt" };
             var path3 = info1.RelativeUrlToFilePath("PKANAVOS");
-            Assert.AreEqual(@"somefolder\file1.txt", path1);
+            Assert.AreEqual(@"pithos\somefolder\file1.txt", path1);
 
         }
 
@@ -75,7 +75,7 @@ namespace Pithos.Network.Test
             var permissionString = objectInfo.GetPermissionString();
 
             Assert.IsNotNullOrEmpty(permissionString);
-            Assert.AreEqual("read=user1;write=user2",permissionString);
+            Assert.AreEqual("read=user1;write=user2",Uri.UnescapeDataString(permissionString));
         }
 
         [Test]
@@ -96,5 +96,44 @@ namespace Pithos.Network.Test
             Assert.IsTrue(objectInfo.Permissions["user3@somehost.gr"]=="write");
 
         }
+
+        [Test]
+        public void empty_should_be_writable()
+        {
+            Assert.That(ObjectInfo.Empty.IsWritable("somAccount"),Is.True);
+        }
+
+        [Test]
+        public void should_be_writeable_for_write_permission()
+        {
+            var objectInfo = new ObjectInfo();
+            var permissionString = "read=user1;write=user2,user3@somehost.gr";
+            objectInfo.SetPermissions(permissionString);
+
+            Assert.That(objectInfo.IsWritable("user3@somehost.gr"),Is.True);
+
+        }
+
+        [Test]
+        public void should_not_be_writeable_for_read_permission()
+        {
+            var objectInfo = new ObjectInfo();
+            var permissionString = "read=user1;write=user2,user3@somehost.gr";
+            objectInfo.SetPermissions(permissionString);
+
+            Assert.That(objectInfo.IsWritable("user1"),Is.False);
+
+        }
+
+        [Test]
+        public void should_not_be_writeable_for_allowed()
+        {
+            var objectInfo = new ObjectInfo{AllowedTo="write"};
+            var permissionString = "read=user1;write=user2,user3@somehost.gr";
+            objectInfo.SetPermissions(permissionString);
+
+            Assert.That(objectInfo.IsWritable("user4"),Is.True);
+
+        }
     }
 }
index 9014a78..8afffb2 100644 (file)
@@ -1393,6 +1393,41 @@ namespace Pithos.Network
             var directories=this.ListObjects(container.Account, container.Name, "/");
         }
 */
+
+        public bool CanUpload(string account, ObjectInfo cloudFile)
+        {
+            Contract.Requires(!String.IsNullOrWhiteSpace(account));
+            Contract.Requires(cloudFile!=null);
+
+            using (var client = new RestClient(_baseClient))
+            {
+                if (!String.IsNullOrWhiteSpace(account))
+                    client.BaseAddress = GetAccountUrl(account);
+
+
+                var parts = cloudFile.Name.Split('/');
+                var folder = String.Join("/", parts,0,parts.Length-1);
+
+                var fileUrl=String.Format("{0}/{1}/{2}.pithos.ignore",cloudFile.Container,folder,Guid.NewGuid());
+
+                client.Parameters.Clear();
+                try
+                {
+                    client.PutWithRetry(fileUrl, 3, @"application/octet-stream");
+
+                    var expectedCodes = new[] { HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created};
+                    return (expectedCodes.Contains(client.StatusCode));
+                }
+                catch
+                {
+                    return false;
+                }
+                finally
+                {
+                    DeleteObject(account,cloudFile.Container,fileUrl);                    
+                }                
+            }
+        }
     }
 
     public class ShareAccountInfo
index 45e0420..865e818 100644 (file)
@@ -307,9 +307,9 @@ namespace Pithos.Network
             RetryWithoutContent(address, retries, "HEAD");
         }
 
-        public void PutWithRetry(string address, int retries = 0)
+        public void PutWithRetry(string address, int retries = 0, string contentType=null)
         {
-            RetryWithoutContent(address, retries, "PUT");
+            RetryWithoutContent(address, retries, "PUT",contentType);
         }
 
         public void PostWithRetry(string address,string contentType)