/// <summary> /// Gets list of files and folders in this folder in the remote storage. /// </summary> /// <param name="pattern">Search pattern.</param> /// <returns> /// List of files and folders located in this folder in the remote /// storage that correstonds with the provided search pattern. /// </returns> public async Task <IEnumerable <FileSystemItemBasicInfo> > EnumerateChildrenAsync(string pattern) { // This method has a 60 sec timeout. // To process longer requests modify the IFolder.GetChildrenAsync() implementation. IHierarchyItemAsync[] remoteStorageChildren = null; // Retry the request in case the log-in dialog is shown. try { remoteStorageChildren = await Program.DavClient.GetChildrenAsync(new Uri(RemoteStorageUri), false); } catch (ITHit.WebDAV.Client.Exceptions.Redirect302Exception) { remoteStorageChildren = await Program.DavClient.GetChildrenAsync(new Uri(RemoteStorageUri), false); } List <FileSystemItemBasicInfo> userFileSystemChildren = new List <FileSystemItemBasicInfo>(); foreach (IHierarchyItemAsync remoteStorageItem in remoteStorageChildren) { FileSystemItemBasicInfo itemInfo = Mapping.GetUserFileSystemItemBasicInfo(remoteStorageItem); userFileSystemChildren.Add(itemInfo); } return(userFileSystemChildren); }
/// <summary> /// Called when a file or folder is created in the remote storage. /// </summary> /// <remarks>In this method we create a new file/folder in user file system.</remarks> private async void CreatedAsync(object sender, FileSystemEventArgs e) { LogMessage(e.ChangeType.ToString(), e.FullPath); string remoteStoragePath = e.FullPath; try { // We do not want to sync MS Office temp files from remote storage. if (!FsPath.AvoidSync(remoteStoragePath)) { string userFileSystemPath = Mapping.ReverseMapPath(remoteStoragePath); string userFileSystemParentPath = Path.GetDirectoryName(userFileSystemPath); // Because of the on-demand population the file or folder placeholder may not exist in the user file system // or the folder may be offline. if (Directory.Exists(userFileSystemParentPath) && !new DirectoryInfo(userFileSystemParentPath).Attributes.HasFlag(System.IO.FileAttributes.Offline)) { FileSystemInfo remoteStorageItem = FsPath.GetFileSystemItem(remoteStoragePath); FileSystemItemBasicInfo newItemInfo = Mapping.GetUserFileSysteItemBasicInfo(remoteStorageItem); await UserFileSystemRawItem.CreateAsync(userFileSystemParentPath, new[] { newItemInfo }); LogMessage($"Created succesefully", userFileSystemPath); } } } catch (Exception ex) { LogError($"{e.ChangeType} failed", remoteStoragePath, null, ex); } }
//$> //$<PlaceholderItem.SetItemInfo /// <summary> /// Updates information about the file or folder placeholder in the user file system. /// This method automatically hydrates and dehydrate files. /// </summary> /// <remarks>This method failes if the file or folder in user file system is modified (not in-sync with the remote storage).</remarks> /// <param name="itemInfo">New file or folder info.</param> /// <returns>True if the file was updated. False - otherwise.</returns> public async Task <bool> UpdateAsync(FileSystemItemBasicInfo itemInfo) { try { // Because of the on-demand population the file or folder placeholder may not exist in the user file system. if (FsPath.Exists(userFileSystemPath)) { PlaceholderItem placeholderItem = PlaceholderItem.GetItem(userFileSystemPath); // To be able to update the item we need to remove the read-only attribute. if ((FsPath.GetFileSystemItem(userFileSystemPath).Attributes | System.IO.FileAttributes.ReadOnly) != 0) { FsPath.GetFileSystemItem(userFileSystemPath).Attributes &= ~System.IO.FileAttributes.ReadOnly; } // Dehydrate/hydrate the file, update file size, custom data, creation date, modification date, attributes. placeholderItem.SetItemInfo(itemInfo); // Set ETag. await ETag.SetETagAsync(userFileSystemPath, itemInfo.ETag); // Clear icon. //await ClearStateAsync(); // Set the "locked by another user" icon and all custom columns data. await SetLockedByAnotherUserAsync(itemInfo.LockedByAnotherUser); await SetCustomColumnsDataAsync(itemInfo.CustomProperties); return(true); } } catch (Exception ex) { await SetDownloadErrorStateAsync(ex); // Rethrow the exception preserving stack trace of the original exception. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); } return(false); }
/// <summary> /// Updates information about the file or folder placeholder in the user file system. /// This method automatically hydrates and dehydrate files. /// </summary> /// <remarks>This method failes if the file or folder in user file system is modified (not in-sync with the remote storage).</remarks> /// <param name="remoteStorageItem">Remote storage item info. The placeholder info will be updated with info provided in this item.</param> internal async Task UpdateAsync(FileSystemInfo remoteStorageItem) { /* * // Process conflicts. File <-> Folder. Folder <-> File. * if (File.Exists(userFileSystemPath) && (remoteStorageItem is DirectoryInfo)) * { * } * else if (Directory.Exists(userFileSystemPath) && (remoteStorageItem is FileInfo)) * { * } */ FileSystemItemBasicInfo userFileSystemItemInfo = Mapping.GetUserFileSysteItemInfo(remoteStorageItem); try { // Dehydrate/hydrate the file, update file size and info. PlaceholderItem.GetItem(userFileSystemPath).SetItemInfo(userFileSystemItemInfo); // Clear download pending icon await SetDownloadPendingIconAsync(false); } catch (System.ComponentModel.Win32Exception ex) { if (ex.NativeErrorCode == 802) { // The file is blocked by the client application or pinned. // "The operation did not complete successfully because it would cause an oplock to be broken. // The caller has requested that existing oplocks not be broken." // Show download pending icon. await SetDownloadPendingIconAsync(true); } // Rethrow the exception preserving stack trace of the original exception. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); } }
/// <summary> /// Called when a file content changed or file/folder attributes changed in the remote storage. /// </summary> /// <remarks> /// In this method we update corresponding file/folder information in user file system. /// We also dehydrate the file if it is not blocked. /// </remarks> private async void ChangedAsync(object sender, FileSystemEventArgs e) { LogMessage(e.ChangeType.ToString(), e.FullPath); string remoteStoragePath = e.FullPath; try { // We do not want to sync MS Office temp files, etc. from remote storage. if (!FsPath.AvoidSync(remoteStoragePath)) { string userFileSystemPath = Mapping.ReverseMapPath(remoteStoragePath); // Because of the on-demand population the file or folder placeholder may not exist in the user file system. if (FsPath.Exists(userFileSystemPath)) { FileSystemInfo remoteStorageItem = FsPath.GetFileSystemItem(remoteStoragePath); // This check is only required because we can not prevent circular calls because of the simplicity of this example. // In your real-life application you will not sent updates from server back to client that issued the update. FileSystemItemBasicInfo itemInfo = Mapping.GetUserFileSysteItemBasicInfo(remoteStorageItem); if (!await ETag.ETagEqualsAsync(userFileSystemPath, itemInfo)) { await new UserFileSystemRawItem(userFileSystemPath).UpdateAsync(itemInfo); LogMessage("Updated succesefully", userFileSystemPath); } // Update "locked by another user" icon. await new UserFileSystemRawItem(userFileSystemPath).SetLockedByAnotherUserAsync(itemInfo.LockedByAnotherUser); } } } catch (Exception ex) { LogError($"{e.ChangeType} failed", remoteStoragePath, null, ex); } }
/// <summary> /// Recursively synchronizes all files and folders from server to client. /// Synchronizes only folders already loaded into the user file system. /// </summary> /// <param name="userFileSystemFolderPath">Folder path in user file system.</param> internal async Task SyncronizeFolderAsync(string userFileSystemFolderPath) { // In case of on-demand loading the user file system contains only a subset of the server files and folders. // Here we sync folder only if its content already loaded into user file system (folder is not offline). // The folder content is loaded inside IFolder.GetChildrenAsync() method. if (new DirectoryInfo(userFileSystemFolderPath).Attributes.HasFlag(System.IO.FileAttributes.Offline)) { // LogMessage("Folder offline, skipping:", userFileSystemFolderPath); return; } IEnumerable <string> userFileSystemChildren = Directory.EnumerateFileSystemEntries(userFileSystemFolderPath, "*"); //LogMessage("Synchronizing:", userFileSystemFolderPath); IEnumerable <FileSystemItemBasicInfo> remoteStorageChildrenItems = await new UserFolder(userFileSystemFolderPath).EnumerateChildrenAsync("*"); // Create new files/folders in the user file system. string remoteStorageFolderPath = Mapping.MapPath(userFileSystemFolderPath); foreach (FileSystemItemBasicInfo remoteStorageItem in remoteStorageChildrenItems) { string userFileSystemPath = Path.Combine(userFileSystemFolderPath, remoteStorageItem.Name); try { // We do not want to sync MS Office temp files, etc. from remote storage. // We also do not want to create MS Office files during transactional save in user file system. string remoteStorageItemFullPath = Path.Combine(remoteStorageFolderPath, remoteStorageItem.Name); if (!FsPath.AvoidSync(remoteStorageItemFullPath) && !FsPath.AvoidSync(userFileSystemPath)) { if (!FsPath.Exists(userFileSystemPath)) { LogMessage($"Creating", userFileSystemPath); await UserFileSystemRawItem.CreateAsync(userFileSystemFolderPath, new[] { remoteStorageItem }); LogMessage($"Created succesefully", userFileSystemPath); } } } catch (Exception ex) { LogError("Creation failed", userFileSystemPath, null, ex); } } // Update files/folders in user file system and sync subfolders. userFileSystemChildren = Directory.EnumerateFileSystemEntries(userFileSystemFolderPath, "*"); foreach (string userFileSystemPath in userFileSystemChildren) { try { string itemName = Path.GetFileName(userFileSystemPath); string remoteStoragePath = Mapping.MapPath(userFileSystemPath); FileSystemItemBasicInfo remoteStorageItem = remoteStorageChildrenItems.FirstOrDefault(x => x.Name.Equals(itemName, StringComparison.InvariantCultureIgnoreCase)); if (!FsPath.AvoidSync(userFileSystemPath) && !FsPath.AvoidSync(remoteStoragePath)) { if (remoteStorageItem == null) { if (PlaceholderItem.GetItem(userFileSystemPath).GetInSync()) { // Delete the file/folder in user file system. LogMessage("Deleting item", userFileSystemPath); await new UserFileSystemRawItem(userFileSystemPath).DeleteAsync(); LogMessage("Deleted succesefully", userFileSystemPath); } } else { if (PlaceholderItem.GetItem(userFileSystemPath).GetInSync() && !await ETag.ETagEqualsAsync(userFileSystemPath, remoteStorageItem)) { // User file system <- remote storage update. LogMessage("Item modified", remoteStoragePath); await new UserFileSystemRawItem(userFileSystemPath).UpdateAsync(remoteStorageItem); LogMessage("Updated succesefully", userFileSystemPath); } // Update "locked by another user" icon. if (PlaceholderItem.GetItem(userFileSystemPath).GetInSync()) { await new UserFileSystemRawItem(userFileSystemPath).SetLockedByAnotherUserAsync(remoteStorageItem.LockedByAnotherUser); } // Hydrate / dehydrate the file. if (new UserFileSystemRawItem(userFileSystemPath).HydrationRequired()) { LogMessage("Hydrating", userFileSystemPath); new PlaceholderFile(userFileSystemPath).Hydrate(0, -1); LogMessage("Hydrated succesefully", userFileSystemPath); } else if (new UserFileSystemRawItem(userFileSystemPath).DehydrationRequired()) { LogMessage("Dehydrating", userFileSystemPath); new PlaceholderFile(userFileSystemPath).Dehydrate(0, -1); LogMessage("Dehydrated succesefully", userFileSystemPath); } } } } catch (Exception ex) { LogError("Update failed", userFileSystemPath, null, ex); } // Synchronize subfolders. try { if (Directory.Exists(userFileSystemPath)) { await SyncronizeFolderAsync(userFileSystemPath); } } catch (Exception ex) { LogError("Folder sync failed:", userFileSystemPath, null, ex); } } }