Revision 8f918cb0
b/trunk/Pithos.Core/Agents/StatusAgent.cs | ||
---|---|---|
350 | 350 |
{ |
351 | 351 |
var createdState = FileState.CreateFor(FileInfoExtensions.FromPath(path)); |
352 | 352 |
createdState.FileStatus = status; |
353 |
_persistenceAgent.Post(createdState.Create);
|
|
353 |
createdState.Create();
|
|
354 | 354 |
} |
355 | 355 |
return affected; |
356 | 356 |
} |
... | ... | |
390 | 390 |
var createdState=FileState.CreateFor(FileInfoExtensions.FromPath(absolutePath)); |
391 | 391 |
createdState.FileStatus = fileStatus; |
392 | 392 |
createdState.OverlayStatus = overlayStatus; |
393 |
_persistenceAgent.Post(createdState.Create);
|
|
393 |
createdState.Create();
|
|
394 | 394 |
} |
395 | 395 |
return affected; |
396 | 396 |
} |
b/trunk/Pithos.Core/Agents/Uploader.cs | ||
---|---|---|
83 | 83 |
{ |
84 | 84 |
|
85 | 85 |
var client = new CloudFilesClient(accountInfo); |
86 |
|
|
86 | 87 |
//Even if GetObjectInfo times out, we can proceed with the upload |
87 | 88 |
var cloudInfo = client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name); |
88 | 89 |
|
89 |
//If this is a read-only file, do not upload changes |
|
90 |
if (!cloudInfo.IsWritable(action.AccountInfo.UserName)) |
|
91 |
return; |
|
90 |
//If this a shared file |
|
91 |
if (!cloudFile.Account.Equals(action.AccountInfo.UserName,StringComparison.InvariantCultureIgnoreCase)) |
|
92 |
{ |
|
93 |
//If this is a read-only file, do not upload changes |
|
94 |
if (!cloudInfo.IsWritable(action.AccountInfo.UserName)) |
|
95 |
{ |
|
96 |
MakeFileReadOnly(fullFileName); |
|
97 |
return; |
|
98 |
} |
|
92 | 99 |
|
93 |
//TODO: If the object does not exist, check that we can upload to the folder |
|
100 |
//If the file is new, can we upload it? |
|
101 |
if ( !cloudInfo.Exists && !client.CanUpload(account, cloudFile)) |
|
102 |
{ |
|
103 |
MakeFileReadOnly(fullFileName); |
|
104 |
return; |
|
105 |
} |
|
106 |
|
|
107 |
} |
|
94 | 108 |
|
95 | 109 |
if (fileInfo is DirectoryInfo) |
96 | 110 |
{ |
... | ... | |
143 | 157 |
if (response.StatusCode == HttpStatusCode.Forbidden) |
144 | 158 |
{ |
145 | 159 |
StatusKeeper.SetFileState(fileInfo.FullName, FileStatus.Forbidden, FileOverlayStatus.Conflict, "Forbidden"); |
146 |
|
|
160 |
MakeFileReadOnly(fullFileName); |
|
147 | 161 |
} |
148 | 162 |
else |
149 | 163 |
//In any other case, propagate the error |
... | ... | |
177 | 191 |
} |
178 | 192 |
} |
179 | 193 |
|
194 |
private static void MakeFileReadOnly(string fullFileName) |
|
195 |
{ |
|
196 |
var attributes = File.GetAttributes(fullFileName); |
|
197 |
//Do not make any modifications if not necessary |
|
198 |
if (attributes.HasFlag(FileAttributes.ReadOnly)) |
|
199 |
return; |
|
200 |
File.SetAttributes(fullFileName, attributes | FileAttributes.ReadOnly); |
|
201 |
} |
|
202 |
|
|
180 | 203 |
private static AccountInfo GetSharerAccount(string relativePath, AccountInfo accountInfo) |
181 | 204 |
{ |
182 | 205 |
var parts = relativePath.Split('\\'); |
b/trunk/Pithos.Network.Test/ObjectInfoTest.cs | ||
---|---|---|
18 | 18 |
|
19 | 19 |
var info1 = new ObjectInfo {Account = "pkanavos", Container = "pithos", Name = "somefolder/file1.txt"}; |
20 | 20 |
var path1=info1.RelativeUrlToFilePath("PKANAVOS"); |
21 |
Assert.AreEqual(@"somefolder\file1.txt",path1); |
|
21 |
Assert.AreEqual(@"pithos\somefolder\file1.txt",path1);
|
|
22 | 22 |
var path2 = info1.RelativeUrlToFilePath("user1"); |
23 |
Assert.AreEqual(@"others\pkanavos\somefolder\file1.txt", path2);
|
|
23 |
Assert.AreEqual(@"others-shared\pkanavos\pithos\somefolder\file1.txt", path2);
|
|
24 | 24 |
var info3 = new ObjectInfo { Account = "pkanavos", Name = "somefolder/file1.txt" }; |
25 | 25 |
var path3 = info1.RelativeUrlToFilePath("PKANAVOS"); |
26 |
Assert.AreEqual(@"somefolder\file1.txt", path1); |
|
26 |
Assert.AreEqual(@"pithos\somefolder\file1.txt", path1);
|
|
27 | 27 |
|
28 | 28 |
} |
29 | 29 |
|
... | ... | |
75 | 75 |
var permissionString = objectInfo.GetPermissionString(); |
76 | 76 |
|
77 | 77 |
Assert.IsNotNullOrEmpty(permissionString); |
78 |
Assert.AreEqual("read=user1;write=user2",permissionString);
|
|
78 |
Assert.AreEqual("read=user1;write=user2",Uri.UnescapeDataString(permissionString));
|
|
79 | 79 |
} |
80 | 80 |
|
81 | 81 |
[Test] |
... | ... | |
96 | 96 |
Assert.IsTrue(objectInfo.Permissions["user3@somehost.gr"]=="write"); |
97 | 97 |
|
98 | 98 |
} |
99 |
|
|
100 |
[Test] |
|
101 |
public void empty_should_be_writable() |
|
102 |
{ |
|
103 |
Assert.That(ObjectInfo.Empty.IsWritable("somAccount"),Is.True); |
|
104 |
} |
|
105 |
|
|
106 |
[Test] |
|
107 |
public void should_be_writeable_for_write_permission() |
|
108 |
{ |
|
109 |
var objectInfo = new ObjectInfo(); |
|
110 |
var permissionString = "read=user1;write=user2,user3@somehost.gr"; |
|
111 |
objectInfo.SetPermissions(permissionString); |
|
112 |
|
|
113 |
Assert.That(objectInfo.IsWritable("user3@somehost.gr"),Is.True); |
|
114 |
|
|
115 |
} |
|
116 |
|
|
117 |
[Test] |
|
118 |
public void should_not_be_writeable_for_read_permission() |
|
119 |
{ |
|
120 |
var objectInfo = new ObjectInfo(); |
|
121 |
var permissionString = "read=user1;write=user2,user3@somehost.gr"; |
|
122 |
objectInfo.SetPermissions(permissionString); |
|
123 |
|
|
124 |
Assert.That(objectInfo.IsWritable("user1"),Is.False); |
|
125 |
|
|
126 |
} |
|
127 |
|
|
128 |
[Test] |
|
129 |
public void should_not_be_writeable_for_allowed() |
|
130 |
{ |
|
131 |
var objectInfo = new ObjectInfo{AllowedTo="write"}; |
|
132 |
var permissionString = "read=user1;write=user2,user3@somehost.gr"; |
|
133 |
objectInfo.SetPermissions(permissionString); |
|
134 |
|
|
135 |
Assert.That(objectInfo.IsWritable("user4"),Is.True); |
|
136 |
|
|
137 |
} |
|
99 | 138 |
} |
100 | 139 |
} |
b/trunk/Pithos.Network/CloudFilesClient.cs | ||
---|---|---|
1393 | 1393 |
var directories=this.ListObjects(container.Account, container.Name, "/"); |
1394 | 1394 |
} |
1395 | 1395 |
*/ |
1396 |
|
|
1397 |
public bool CanUpload(string account, ObjectInfo cloudFile) |
|
1398 |
{ |
|
1399 |
Contract.Requires(!String.IsNullOrWhiteSpace(account)); |
|
1400 |
Contract.Requires(cloudFile!=null); |
|
1401 |
|
|
1402 |
using (var client = new RestClient(_baseClient)) |
|
1403 |
{ |
|
1404 |
if (!String.IsNullOrWhiteSpace(account)) |
|
1405 |
client.BaseAddress = GetAccountUrl(account); |
|
1406 |
|
|
1407 |
|
|
1408 |
var parts = cloudFile.Name.Split('/'); |
|
1409 |
var folder = String.Join("/", parts,0,parts.Length-1); |
|
1410 |
|
|
1411 |
var fileUrl=String.Format("{0}/{1}/{2}.pithos.ignore",cloudFile.Container,folder,Guid.NewGuid()); |
|
1412 |
|
|
1413 |
client.Parameters.Clear(); |
|
1414 |
try |
|
1415 |
{ |
|
1416 |
client.PutWithRetry(fileUrl, 3, @"application/octet-stream"); |
|
1417 |
|
|
1418 |
var expectedCodes = new[] { HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created}; |
|
1419 |
return (expectedCodes.Contains(client.StatusCode)); |
|
1420 |
} |
|
1421 |
catch |
|
1422 |
{ |
|
1423 |
return false; |
|
1424 |
} |
|
1425 |
finally |
|
1426 |
{ |
|
1427 |
DeleteObject(account,cloudFile.Container,fileUrl); |
|
1428 |
} |
|
1429 |
} |
|
1430 |
} |
|
1396 | 1431 |
} |
1397 | 1432 |
|
1398 | 1433 |
public class ShareAccountInfo |
b/trunk/Pithos.Network/RestClient.cs | ||
---|---|---|
307 | 307 |
RetryWithoutContent(address, retries, "HEAD"); |
308 | 308 |
} |
309 | 309 |
|
310 |
public void PutWithRetry(string address, int retries = 0) |
|
310 |
public void PutWithRetry(string address, int retries = 0, string contentType=null)
|
|
311 | 311 |
{ |
312 |
RetryWithoutContent(address, retries, "PUT"); |
|
312 |
RetryWithoutContent(address, retries, "PUT",contentType);
|
|
313 | 313 |
} |
314 | 314 |
|
315 | 315 |
public void PostWithRetry(string address,string contentType) |
Also available in: Unified diff