/// <summary> /// Recursively restores OriginalPath and the 'locked' icon. /// </summary> /// <param name="userFileSystemNewPath">Path in the user file system to start recursive processing.</param> private async Task MoveToCompletionRecursiveAsync(string userFileSystemNewPath) { if (FsPath.IsFolder(userFileSystemNewPath)) { if (!new DirectoryInfo(userFileSystemNewPath).Attributes.HasFlag(System.IO.FileAttributes.Offline)) { //LogMessage("Folder offline, skipping:", userFileSystemFolderPath); IEnumerable <string> userFileSystemChildren = Directory.EnumerateFileSystemEntries(userFileSystemNewPath, "*"); foreach (string userFileSystemChildPath in userFileSystemChildren) { try { await MoveToCompletionRecursiveAsync(userFileSystemChildPath); } catch (Exception ex) { logger.LogError("Failed to complete move", userFileSystemChildPath, null, ex); } } } } if (FsPath.Exists(userFileSystemNewPath) && // This check is just to avoid extra error in the log. !FsPath.IsRecycleBin(userFileSystemNewPath) && // When a file with content is deleted, it is moved to a Recycle Bin. !FsPath.AvoidAutoLock(userFileSystemNewPath)) // No need to update temp MS Office docs. { // Open file to prevent reads and changes between GetFileDataSizeInfo() call and SetInSync() call. using (WindowsFileSystemItem userFileSystemWinItem = WindowsFileSystemItem.OpenReadAttributes(userFileSystemNewPath, FileMode.Open, FileShare.None)) { // If a file with content is deleted it is moved to a recycle bin and converted // to a regular file, so placeholder features are not available on it, checking if a file is a placeholder. if (/*updateTargetOnSuccess &&*/ PlaceholderItem.IsPlaceholder(userFileSystemNewPath)) { PlaceholderItem placeholderNew = PlaceholderItem.GetItem(userFileSystemNewPath); await virtualDrive.GetUserFileSystemRawItem(userFileSystemNewPath, logger).ClearStateAsync(); // Update OriginalPath if the item is not new. // Required for pptx and xlsx files Save As operation. if (!placeholderNew.IsNew(virtualDrive)) { // Update OriginalPath, so the item does not appear as moved. logger.LogMessage("Setting Original Path", userFileSystemNewPath); placeholderNew.SetOriginalPath(userFileSystemNewPath); } // Restore the 'locked' icon. ServerLockInfo existingLock = await virtualDrive.LockManager(userFileSystemNewPath, logger).GetLockInfoAsync(); await virtualDrive.GetUserFileSystemRawItem(userFileSystemNewPath, logger).SetLockInfoAsync(existingLock); } } } }
/// <summary> /// Moves a file or folder placeholder in user file system. /// </summary> /// <param name="userFileSystemNewPath">New path in user file system.</param> /// <remarks> /// This method failes if the file or folder in user file system is modified (not in sync with the remote storage) /// or if the target file exists. /// </remarks> public async Task MoveToAsync(string userFileSystemNewPath) { // Cloud Filter API does not provide a function to move a placeholder file only if it is not modified. // The file may be modified between InSync call, Move() call and SetInSync() in this method. try { // Because of the on-demand population the file or folder placeholder may not exist in the user file system. if (FsPath.Exists(userFileSystemPath)) { bool inSync = PlaceholderItem.GetItem(userFileSystemPath).GetInSync(); if (inSync) { string eTag = await ETag.GetETagAsync(userFileSystemPath); ETag.DeleteETag(userFileSystemPath); try { Directory.Move(userFileSystemPath, userFileSystemNewPath); } catch { await ETag.SetETagAsync(userFileSystemPath, eTag); throw; } await ETag.SetETagAsync(userFileSystemNewPath, eTag); // The file is marked as not in sync after move/rename. Marking it as in-sync. PlaceholderItem placeholderItem = PlaceholderItem.GetItem(userFileSystemNewPath); placeholderItem.SetInSync(true); placeholderItem.SetOriginalPath(userFileSystemNewPath); await new UserFileSystemRawItem(userFileSystemNewPath).ClearStateAsync(); } if (!inSync) { throw new ConflictException(Modified.Client, "The item is not in-sync with the cloud."); } } } catch (Exception ex) { string path = FsPath.Exists(userFileSystemNewPath) ? userFileSystemNewPath : userFileSystemPath; await new UserFileSystemRawItem(userFileSystemPath).SetDownloadErrorStateAsync(ex); // Rethrow the exception preserving stack trace of the original exception. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); } }
/// <summary> /// Moves a file or folder placeholder in user file system. /// </summary> /// <param name="userFileSystemNewPath">New path in user file system.</param> /// <remarks> /// This method failes if the file or folder in user file system is modified (not in sync with the remote storage) /// or if the target file exists. /// </remarks> /// <returns>True if the item was moved. False - otherwise.</returns> public async Task <bool> MoveToAsync(string userFileSystemNewPath) { // Cloud Filter API does not provide a function to move a placeholder file only if it is not modified. // The file may be modified between InSync call, Move() call and SetInSync() in this method. bool itemMoved = false; try { // Because of the on-demand population the file or folder placeholder may not exist in the user file system. if (FsPath.Exists(userFileSystemPath)) { bool inSync = PlaceholderItem.GetItem(userFileSystemPath).GetInSync(); if (inSync) { logger.LogMessage("Moving ETag", userFileSystemPath, userFileSystemNewPath); await eTagManager.MoveToAsync(userFileSystemNewPath); logger.LogMessage("Moving item", userFileSystemPath, userFileSystemNewPath); await virtualDrive.Engine.ServerNotifications(userFileSystemPath).MoveToAsync(userFileSystemNewPath); // The file is marked as not in sync after move/rename. Marking it as in-sync. PlaceholderItem placeholderItem = PlaceholderItem.GetItem(userFileSystemNewPath); placeholderItem.SetInSync(true); placeholderItem.SetOriginalPath(userFileSystemNewPath); await virtualDrive.GetUserFileSystemRawItem(userFileSystemNewPath, logger).ClearStateAsync(); itemMoved = true; } if (!inSync) { throw new ConflictException(Modified.Client, "The item is not in-sync with the cloud."); } } } catch (Exception ex) { string userFileSystemExPath = FsPath.Exists(userFileSystemNewPath) ? userFileSystemNewPath : userFileSystemPath; await virtualDrive.GetUserFileSystemRawItem(userFileSystemExPath, logger).SetDownloadErrorStateAsync(ex); // Rethrow the exception preserving stack trace of the original exception. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); } return(itemMoved); }
//$<IFileSystemItem.MoveToAsync ///<inheritdoc> public async Task MoveToAsync(string userFileSystemNewPath, IOperationContext operationContext, IConfirmationResultContext resultContext) { string userFileSystemOldPath = this.UserFileSystemPath; Logger.LogMessage("IFileSystemItem.MoveToAsync()", userFileSystemOldPath, userFileSystemNewPath); // Process move. if (Engine.ChangesProcessingEnabled) { if (FsPath.Exists(userFileSystemOldPath)) { await new RemoteStorageRawItem(userFileSystemOldPath, VirtualDrive, Logger).MoveToAsync(userFileSystemNewPath, resultContext); } } else { resultContext.ReturnConfirmationResult(); } // Restore Original Path and locked icon, lost during MS Office transactional save. if (FsPath.Exists(userFileSystemNewPath) && PlaceholderItem.IsPlaceholder(userFileSystemNewPath)) { PlaceholderItem userFileSystemNewItem = PlaceholderItem.GetItem(userFileSystemNewPath); if (!userFileSystemNewItem.IsNew() && string.IsNullOrEmpty(userFileSystemNewItem.GetOriginalPath())) { // Restore Original Path. Logger.LogMessage("Saving Original Path", userFileSystemNewPath); userFileSystemNewItem.SetOriginalPath(userFileSystemNewPath); // Restore the 'locked' icon. bool isLocked = await Lock.IsLockedAsync(userFileSystemNewPath); ServerLockInfo existingLock = isLocked ? await(await Lock.LockAsync(userFileSystemNewPath, FileMode.Open, LockMode.None, Logger)).GetLockInfoAsync() : null; await new UserFileSystemRawItem(userFileSystemNewPath).SetLockInfoAsync(existingLock); } } }
internal async Task MoveToAsync(string userFileSystemNewPath, IConfirmationResultContext resultContext = null) { string userFileSystemOldPath = userFileSystemPath; try { bool? inSync = null; bool updateTargetOnSuccess = false; string eTag = null; try { if (!FsPath.IsRecycleBin(userFileSystemNewPath) && // When a file is deleted, it is moved to a Recycle Bin. !FsPath.AvoidSync(userFileSystemOldPath) && !FsPath.AvoidSync(userFileSystemNewPath)) { logger.LogMessage("Moving item in remote storage", userFileSystemOldPath, userFileSystemNewPath); // Read In-Sync state before move and set after move if (FsPath.Exists(userFileSystemOldPath)) { inSync = PlaceholderItem.GetItem(userFileSystemOldPath).GetInSync(); } eTag = await ETag.GetETagAsync(userFileSystemOldPath); ETag.DeleteETag(userFileSystemOldPath); IUserFileSystemItem userFileSystemItemOld = await virtualDrive.GetItemAsync <IUserFileSystemItem>(userFileSystemOldPath); await userFileSystemItemOld.MoveToAsync(userFileSystemNewPath); updateTargetOnSuccess = true; logger.LogMessage("Moved succesefully in remote storage", userFileSystemOldPath, userFileSystemNewPath); } } finally { if (resultContext != null) { resultContext.ReturnConfirmationResult(); } // This check is just to avoid extra error in the log. if (FsPath.Exists(userFileSystemNewPath)) { // Open file to preven reads and changes between GetFileDataSizeInfo() call and SetInSync() call. using (WindowsFileSystemItem userFileSystemWinItem = WindowsFileSystemItem.OpenReadAttributes(userFileSystemNewPath, FileMode.Open, FileShare.None)) { if ((eTag != null) && PlaceholderItem.IsPlaceholder(userFileSystemNewPath)) { await ETag.SetETagAsync(userFileSystemNewPath, eTag); } // If a file with content is deleted it is moved to a recycle bin and converted // to a regular file, so placeholder features are not available on it, checking if a file is a placeholder. if (updateTargetOnSuccess && PlaceholderItem.IsPlaceholder(userFileSystemNewPath)) { PlaceholderItem placeholderNew = PlaceholderItem.GetItem(userFileSystemNewPath); // Update OriginalPath, so the item does not appear as moved. placeholderNew.SetOriginalPath(userFileSystemNewPath); if (inSync != null) { placeholderNew.SetInSync(inSync.Value); } else if ((placeholderNew is PlaceholderFile) && ((PlaceholderFile)placeholderNew).GetFileDataSizeInfo().ModifiedDataSize == 0) { placeholderNew.SetInSync(true); } await new UserFileSystemRawItem(userFileSystemNewPath).ClearStateAsync(); } } } } } catch (Exception ex) { string userFileSystemPath = FsPath.Exists(userFileSystemNewPath) ? userFileSystemNewPath : userFileSystemOldPath; await new UserFileSystemRawItem(userFileSystemPath).SetUploadErrorStateAsync(ex); // Rethrow the exception preserving stack trace of the original exception. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); } }
/// <summary> /// Recursively synchronizes all files and folders moved in user file system with the remote storage. /// Synchronizes only folders already loaded into the user file system. /// </summary> /// <param name="userFileSystemFolderPath">Folder path in user file system.</param> internal async Task SyncronizeMovedAsync(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); foreach (string userFileSystemPath in userFileSystemChildren) { string userFileSystemOldPath = null; try { //$<PlaceholderItem.IsPlaceholder if (!PlaceholderItem.IsPlaceholder(userFileSystemPath)) { // Convert regular file/folder to placeholder. // The file/folder was created or overwritten. PlaceholderItem.ConvertToPlaceholder(userFileSystemPath, false); LogMessage("Converted to placeholder", userFileSystemPath); } //$> if (!FsPath.AvoidSync(userFileSystemPath)) { PlaceholderItem userFileSystemItem = PlaceholderItem.GetItem(userFileSystemPath); if (userFileSystemItem.IsMoved()) { // Process items moved in user file system. userFileSystemOldPath = userFileSystemItem.GetOriginalPath(); await new RemoteStorageRawItem(userFileSystemOldPath, this).MoveToAsync(userFileSystemPath); } else { // Restore Original Path and 'locked' icon that are lost during MS Office transactional save. // We keep Original Path to process moved files when app was not running. userFileSystemOldPath = userFileSystemItem.GetOriginalPath(); if (!userFileSystemItem.IsNew() && string.IsNullOrEmpty(userFileSystemOldPath)) { // Restore Original Path. LogMessage("Saving Original Path", userFileSystemItem.Path); userFileSystemItem.SetOriginalPath(userFileSystemItem.Path); // Restore the 'locked' icon. bool isLocked = await Lock.IsLockedAsync(userFileSystemPath); await new UserFileSystemRawItem(userFileSystemPath).SetLockIconAsync(isLocked); } } } } catch (Exception ex) { LogError("Move in remote storage failed", userFileSystemOldPath, userFileSystemPath, ex); } // Synchronize subfolders. try { if (FsPath.IsFolder(userFileSystemPath)) { await SyncronizeMovedAsync(userFileSystemPath); } } catch (Exception ex) { LogError("Folder move sync failed", userFileSystemPath, null, ex); } } }