Skip to content

Commit 58d9417

Browse files
committed
v1.2.3984.0
1 parent 8bdeece commit 58d9417

15 files changed

+140
-54
lines changed

VirtualFileSystem/Framework/FileSystemItemBasicInfo.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,10 @@ internal class FileSystemItemBasicInfo : IFileSystemItemBasicInfo
3737
/// Server ETag.
3838
/// </summary>
3939
public string ETag { get; set; }
40+
41+
/// <summary>
42+
/// Indicates if the item is locked by another user in the remote storage.
43+
/// </summary>
44+
public bool LockedByAnotherUser { get; set; }
4045
}
4146
}

VirtualFileSystem/Framework/FsPath.cs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,39 +121,30 @@ private static bool IsMsOfficeTemp(string path)
121121
{
122122
return (Path.GetFileName(path).StartsWith('~') && Path.GetExtension(path).Equals(".tmp", StringComparison.InvariantCultureIgnoreCase)) // Word temp files
123123
|| (Path.GetFileName(path).StartsWith("ppt") && Path.GetExtension(path).Equals(".tmp", StringComparison.InvariantCultureIgnoreCase)) // PowerPoint temp files
124-
|| (string.IsNullOrEmpty(Path.GetExtension(path)) && (Path.GetFileName(path).Length == 8)) // Excel temp files
124+
|| (string.IsNullOrEmpty(Path.GetExtension(path)) && (Path.GetFileName(path).Length == 8) && File.Exists(path)) // Excel temp files
125125
|| ((Path.GetFileNameWithoutExtension(path).Length == 8) && Path.GetExtension(path).Equals(".tmp", StringComparison.InvariantCultureIgnoreCase)); // Excel temp files
126126
}
127127

128128
/// <summary>
129129
/// Returns true if file system contains MS Office lock file (~$file.ext) in file
130130
/// system that corresponds to the provided path to MS Office file.
131131
/// </summary>
132-
/// <param name="path">Path to MS Office file.</param>
132+
/// <param name="path">Path to the MS Office file.</param>
133133
internal static bool IsMsOfficeLocked(string path)
134134
{
135135
string lockPath = GetLockPathFromMsOfficePath(path);
136136
return lockPath != null;
137137
}
138138

139-
140139
/// <summary>
141140
/// Returns true if the provided path points to MS Office lock file (~$file.ext).
142141
/// </summary>
143-
/// <param name="path">Path to lock file.</param>
142+
/// <param name="path">Path to the MS Office lock file.</param>
144143
internal static bool IsMsOfficeLockFile(string path)
145144
{
146145
return Path.GetFileName(path).StartsWith("~$");
147146
}
148147

149-
150-
//public static string GetMsOfficePathFromLock(string msOfficeLockFilePath)
151-
//{
152-
// int separatorIndex = msOfficeLockFilePath.LastIndexOf(Path.DirectorySeparatorChar);
153-
// return msOfficeLockFilePath.Remove(separatorIndex + 1, "~$".Length);
154-
//}
155-
156-
157148
/// <summary>
158149
/// Returns MS Office lock file path if such file exists.
159150
/// </summary>
@@ -253,7 +244,7 @@ public static string Size(string path)
253244
return null;
254245
}
255246

256-
string[] suf = { "b ", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB
247+
string[] suf = { "b ", "KB", "MB", "GB", "TB", "PB", "EB" };
257248
if (length == 0)
258249
{
259250
return "0" + suf[0];
@@ -271,6 +262,13 @@ public static string Size(string path)
271262
/// <returns>True if the file is locked for writing. False otherwise.</returns>
272263
public static bool IsWriteLocked(string path)
273264
{
265+
// To avoid hydration (typically during the file deletion) we check the Offline attribute.
266+
// If file is marked offline, it is not open for writing.
267+
if (((int)File.GetAttributes(path) & (int)Syncronyzation.FileAttributesExt.Offline) != 0)
268+
{
269+
return false;
270+
}
271+
274272
try
275273
{
276274
using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))

VirtualFileSystem/Framework/Registrar.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ public static async Task RegisterAsync(string syncRootId, string path, string di
3737
// StorageProviderSyncRootInfo.PopulationPolicy to StorageProviderPopulationPolicy.Full.
3838
storageInfo.PopulationPolicy = StorageProviderPopulationPolicy.Full; // Set to Full to list folder content immediately on program start.
3939

40-
storageInfo.InSyncPolicy =
41-
StorageProviderInSyncPolicy.FileLastWriteTime | StorageProviderInSyncPolicy.FileCreationTime |
42-
StorageProviderInSyncPolicy.FileHiddenAttribute | StorageProviderInSyncPolicy.FileReadOnlyAttribute |
43-
StorageProviderInSyncPolicy.FileSystemAttribute | StorageProviderInSyncPolicy.DirectoryLastWriteTime |
44-
StorageProviderInSyncPolicy.DirectoryCreationTime | StorageProviderInSyncPolicy.DirectoryHiddenAttribute |
45-
StorageProviderInSyncPolicy.DirectoryReadOnlyAttribute | StorageProviderInSyncPolicy.DirectorySystemAttribute;
46-
47-
40+
// The read-only attribute is used to indicate that the item is being locked by another user. Do not include it into InSyncPolicy.
41+
storageInfo.InSyncPolicy =
42+
StorageProviderInSyncPolicy.FileCreationTime | StorageProviderInSyncPolicy.DirectoryCreationTime |
43+
StorageProviderInSyncPolicy.FileLastWriteTime | StorageProviderInSyncPolicy.DirectoryLastWriteTime |
44+
StorageProviderInSyncPolicy.FileHiddenAttribute | StorageProviderInSyncPolicy.DirectoryHiddenAttribute |
45+
StorageProviderInSyncPolicy.FileSystemAttribute | StorageProviderInSyncPolicy.DirectorySystemAttribute;
46+
//StorageProviderInSyncPolicy.FileReadOnlyAttribute | StorageProviderInSyncPolicy.DirectoryReadOnlyAttribute;
47+
4848
//storageInfo.ShowSiblingsAsGroup = false;
4949
//storageInfo.HardlinkPolicy = StorageProviderHardlinkPolicy.None;
5050

VirtualFileSystem/Framework/Syncronyzation/ServerToClientSync.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ internal async Task SyncronizeFolderAsync(string userFileSystemFolderPath)
109109
LogMessage("Updated succesefully", userFileSystemPath);
110110
}
111111

112+
// Update "locked by another user" icon.
113+
if(PlaceholderItem.GetItem(userFileSystemPath).GetInSync())
114+
115+
{
116+
await new UserFileSystemRawItem(userFileSystemPath).SetLockedByAnotherUserAsync(remoteStorageItem.LockedByAnotherUser);
117+
}
118+
112119
// Hydrate / dehydrate the file.
113120
if(new UserFileSystemRawItem(userFileSystemPath).HydrationRequired())
114121
{

VirtualFileSystem/Framework/Syncronyzation/UserFileSystemMonitor.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,7 @@ private async void ChangedAsync(object sender, FileSystemEventArgs e)
126126
if (new UserFileSystemRawItem(userFileSystemPath).HydrationRequired())
127127
{
128128
LogMessage("Hydrating", userFileSystemPath);
129-
if (FsPath.IsFolder(userFileSystemPath))
130-
{
131-
// List folder content to create placeholders that will trigger hydration.
132-
//new DirectoryInfo(userFileSystemPath).EnumerateFileSystemInfos("*");
133-
}
134-
else
135-
{
136-
new PlaceholderFile(userFileSystemPath).Hydrate(0, -1);
137-
}
129+
new PlaceholderFile(userFileSystemPath).Hydrate(0, -1);
138130
LogMessage("Hydrated succesefully", userFileSystemPath);
139131
}
140132
else if (new UserFileSystemRawItem(userFileSystemPath).DehydrationRequired())

VirtualFileSystem/Framework/Syncronyzation/UserFileSystemRawItem.cs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ internal static async Task<uint> CreateAsync(string userFileSystemParentPath, Fi
7878
{
7979
string userFileSystemItemPath = Path.Combine(userFileSystemParentPath, child.Name);
8080
await ETag.SetETagAsync(userFileSystemItemPath, child.ETag);
81+
82+
// Set the lock icon and read-only attribute, to indicate that the item is locked by another user.
83+
await new UserFileSystemRawItem(userFileSystemItemPath).SetLockedByAnotherUserAsync(child.LockedByAnotherUser);
8184
}
8285

8386
return created;
@@ -113,14 +116,23 @@ internal async Task<bool> UpdateAsync(FileSystemItemBasicInfo itemInfo)
113116
{
114117
PlaceholderItem placeholderItem = PlaceholderItem.GetItem(userFileSystemPath);
115118

119+
// To be able to update the item we need to remove the read-only attribute.
120+
if((FsPath.GetFileSystemItem(userFileSystemPath).Attributes | System.IO.FileAttributes.ReadOnly) != 0)
121+
{
122+
FsPath.GetFileSystemItem(userFileSystemPath).Attributes &= ~System.IO.FileAttributes.ReadOnly;
123+
}
124+
116125
// Dehydrate/hydrate the file, update file size, custom data, creation date, modification date, attributes.
117126
placeholderItem.SetItemInfo(itemInfo);
118127

119128
// Set ETag.
120129
await ETag.SetETagAsync(userFileSystemPath, itemInfo.ETag);
121130

122131
// Clear icon.
123-
await ClearStateAsync();
132+
//await ClearStateAsync();
133+
134+
// Set the lock icon and read-only attribute, to indicate that the item is locked by another user.
135+
await SetLockedByAnotherUserAsync(itemInfo.LockedByAnotherUser);
124136

125137
return true;
126138
}
@@ -377,6 +389,15 @@ internal async Task SetLockPendingIconAsync(bool set)
377389
await SetIconAsync(set, 2, "LockedPending.ico", "Updating lock...");
378390
}
379391

392+
/// <summary>
393+
/// Sets or removes "Locked another another user" icon.
394+
/// </summary>
395+
/// <param name="set">True to display the icon. False - to remove the icon.</param>
396+
private async Task SetLockedByAnotherUserIconAsync(bool set)
397+
{
398+
await SetIconAsync(set, 2, "LockedByAnotherUser.ico", "The item is locked by another user");
399+
}
400+
380401
/// <summary>
381402
/// Sets or removes icon.
382403
/// </summary>
@@ -430,5 +451,40 @@ private async Task SetIconAsync(bool set, int? id = null, string iconFile = null
430451
}
431452
}
432453
}
454+
455+
/// <summary>
456+
/// Sets or removes "Locked another another user" icon and read-only attribute on files.
457+
/// </summary>
458+
/// <param name="set">True to display the icon and read-only attribute. False - to remove the icon and read-only attribute.</param>
459+
internal async Task SetLockedByAnotherUserAsync(bool set)
460+
{
461+
// Can not set icon on read-only files.
462+
// Changing read-only attribute on folders triggers folders listing. Changing it on files only.
463+
464+
if(FsPath.IsFile(userFileSystemPath))
465+
{
466+
FileInfo file = new FileInfo(userFileSystemPath);
467+
if(set != file.IsReadOnly)
468+
{
469+
// Remove read-only attribute.
470+
new FileInfo(userFileSystemPath).Attributes &= ~System.IO.FileAttributes.ReadOnly;
471+
472+
// Update the lock icon, to indicate that the item is locked by another user.
473+
await SetLockedByAnotherUserIconAsync(set);
474+
475+
// Set read-only attribute.
476+
if (set)
477+
{
478+
new FileInfo(userFileSystemPath).Attributes |= System.IO.FileAttributes.ReadOnly;
479+
}
480+
}
481+
}
482+
else
483+
{
484+
// Update the lock icon, to indicate that the item is locked by another user.
485+
await SetLockedByAnotherUserIconAsync(set);
486+
}
487+
}
488+
433489
}
434490
}

VirtualFileSystem/Framework/VfsFile.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public VfsFile(string path, ILogger logger, VfsEngine engine) : base(path, logge
3030
public async Task OpenAsync(IOperationContext operationContext, IResultContext context)
3131
{
3232
Logger.LogMessage("IFile.OpenAsync()", UserFileSystemPath);
33-
33+
3434
// Auto-lock the file.
3535
string userFileSystemFilePath = UserFileSystemPath;
3636
if (Engine.ChangesProcessingEnabled && FsPath.Exists(userFileSystemFilePath))
@@ -131,7 +131,7 @@ public async Task ValidateDataAsync(long offset, long length, IValidateDataOpera
131131

132132
Logger.LogMessage($"IFile.ValidateDataAsync({offset}, {length})", UserFileSystemPath);
133133

134-
SimulateNetworkDelay(length, resultContext);
134+
//SimulateNetworkDelay(length, resultContext);
135135

136136
bool isValid = await new UserFile(UserFileSystemPath).ValidateDataAsync(offset, length);
137137

VirtualFileSystem/Framework/VfsFolder.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Text;
99
using System.Threading;
1010
using System.Threading.Tasks;
11+
using VirtualFileSystem.Syncronyzation;
1112
using Windows.Storage;
1213

1314
namespace VirtualFileSystem
@@ -51,14 +52,19 @@ public async Task GetChildrenAsync(string pattern, IOperationContext operationCo
5152
resultContext.ReturnChildren(newChildren.ToArray(), newChildren.Count());
5253

5354

54-
// Create ETags.
55-
// ETags must correspond with a server file/folder, NOT with a client placeholder.
56-
// It should NOT be moved/deleted/updated when a placeholder in the user file system is moved/deleted/updated.
57-
// It should be moved/deleted when a file/folder in the remote storage is moved/deleted.
55+
// Save ETags and set "locked by another user" icon.
5856
foreach (FileSystemItemBasicInfo child in children)
5957
{
6058
string userFileSystemItemPath = Path.Combine(UserFileSystemPath, child.Name);
61-
await ETag.SetETagAsync(userFileSystemItemPath, child.ETag);
59+
60+
// Create ETags.
61+
// ETags must correspond with a server file/folder, NOT with a client placeholder.
62+
// It should NOT be moved/deleted/updated when a placeholder in the user file system is moved/deleted/updated.
63+
// It should be moved/deleted when a file/folder in the remote storage is moved/deleted.
64+
ETag.SetETagAsync(userFileSystemItemPath, child.ETag);
65+
66+
// Set the lock icon and read-only attribute, to indicate that the item is locked by another user.
67+
new UserFileSystemRawItem(userFileSystemItemPath).SetLockedByAnotherUserAsync(child.LockedByAnotherUser);
6268
}
6369
}
6470
}
894 Bytes
Binary file not shown.

VirtualFileSystem/Mapping.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ namespace VirtualFileSystem
1515
internal static class Mapping
1616
{
1717
/// <summary>
18-
/// Returns a remote storage path that corresponds to the user file system path.
18+
/// Returns a remote storage URI that corresponds to the user file system path.
1919
/// </summary>
2020
/// <param name="userFileSystemPath">Full path in the user file system.</param>
21-
/// <returns>Path in the remote storage that corresponds to the <paramref name="userFileSystemPath"/>.</returns>
21+
/// <returns>Remote storage URI that corresponds to the <paramref name="userFileSystemPath"/>.</returns>
2222
public static string MapPath(string userFileSystemPath)
2323
{
2424
// Get path relative to the virtual root.
@@ -30,14 +30,14 @@ public static string MapPath(string userFileSystemPath)
3030
}
3131

3232
/// <summary>
33-
/// Returns a user file system path that corresponds to the remote storage path.
33+
/// Returns a user file system path that corresponds to the remote storage URI.
3434
/// </summary>
35-
/// <param name="remoteStoragePath">Full path in the remote storage.</param>
36-
/// <returns>Path in the user file system that corresponds to the <paramref name="remoteStoragePath"/>.</returns>
37-
public static string ReverseMapPath(string remoteStoragePath)
35+
/// <param name="remoteStorageUri">Remote storage URI.</param>
36+
/// <returns>Path in the user file system that corresponds to the <paramref name="remoteStorageUri"/>.</returns>
37+
public static string ReverseMapPath(string remoteStorageUri)
3838
{
3939
// Get path relative to the virtual root.
40-
string relativePath = Path.TrimEndingDirectorySeparator(remoteStoragePath).Substring(
40+
string relativePath = Path.TrimEndingDirectorySeparator(remoteStorageUri).Substring(
4141
Path.TrimEndingDirectorySeparator(Program.Settings.RemoteStorageRootPath).Length);
4242

4343
string path = $"{Path.TrimEndingDirectorySeparator(Program.Settings.UserFileSystemRootPath)}{relativePath}";
@@ -70,12 +70,16 @@ public static FileSystemItemBasicInfo GetUserFileSysteItemBasicInfo(FileSystemIn
7070
userFileSystemItem.ChangeTime = remoteStorageItem.LastWriteTime;
7171

7272
// You will send the ETag to
73-
// the server inside If-Match header togater with updated content from client.
73+
// the server inside If-Match header togeter with updated content from client.
7474
// This will make sure the changes on the server is not overwritten.
7575
//
7676
// In this sample, for the sake of simplicity, we use file last write time instead of ETag.
7777
userFileSystemItem.ETag = remoteStorageItem.LastWriteTime.ToBinary().ToString();
7878

79+
// If the item is locked by another user, set the LockedByAnotherUser to true.
80+
// Here we just use the read-only attribute from remote storage item for demo purposes.
81+
userFileSystemItem.LockedByAnotherUser = (remoteStorageItem.Attributes & System.IO.FileAttributes.ReadOnly) != 0;
82+
7983
// If the file is moved/renamed and the app is not running this will help us
8084
// to sync the file/folder to remote storage after app starts.
8185
userFileSystemItem.CustomData = new CustomData

0 commit comments

Comments
 (0)