コード例 #1
0
        private async Task CreateOrUpdateFolderAsync(string userFileSystemPath, bool create)
        {
            try
            {
                Program.RemoteStorageMonitorInstance.Enabled = false; // Disable RemoteStorageMonitor to avoid circular calls.

                DirectoryInfo userFileSystemFolder = new DirectoryInfo(userFileSystemPath);
                DirectoryInfo remoteStorageFolder  = new DirectoryInfo(remoteStoragePath);

                remoteStorageFolder.Create();

                // Update ETag/LastWriteTime in user file system, so the synchronyzation or remote storage monitor would not start the new update.
                byte[] customData = BitConverter.GetBytes(userFileSystemFolder.LastWriteTime.ToBinary());
                PlaceholderItem.GetItem(userFileSystemPath).SetCustomData(customData);

                // Remove Pinned, Unpinned and Offline flags.
                remoteStorageFolder.Attributes =
                    userFileSystemFolder.Attributes
                    & (FileAttributes) ~FileAttributesExt.Pinned
                    & (FileAttributes) ~FileAttributesExt.Unpinned
                    & ~FileAttributes.Offline;

                remoteStorageFolder.CreationTimeUtc   = userFileSystemFolder.CreationTimeUtc;
                remoteStorageFolder.LastWriteTimeUtc  = userFileSystemFolder.LastWriteTimeUtc;
                remoteStorageFolder.LastAccessTimeUtc = userFileSystemFolder.LastAccessTimeUtc;
                remoteStorageFolder.LastWriteTimeUtc  = userFileSystemFolder.LastWriteTimeUtc;

                PlaceholderItem.GetItem(userFileSystemPath).SetInSync(true);
            }
            finally
            {
                Program.RemoteStorageMonitorInstance.Enabled = true;
            }
        }
コード例 #2
0
        ///<inheritdoc>
        public async Task MoveToAsync(string userFileSystemNewPath, IOperationContext operationContext, IConfirmationResultContext resultContext)
        {
            // Here we will simply move the file in remote storage and confirm the operation.
            // In your implementation you may implement a more complex scenario with offline operations support.

            LogMessage("IFileSystemItem.MoveToAsync()", this.FullPath, userFileSystemNewPath);

            string userFileSystemOldPath = this.FullPath;

            try
            {
                bool?inSync = null;
                try
                {
                    Program.RemoteStorageMonitorInstance.Enabled = false; // Disable RemoteStorageMonitor to avoid circular calls.

                    // When a file is deleted, it is moved to a Recycle Bin, that is why we check for recycle bin here.
                    if (FsPath.Exists(userFileSystemOldPath) && !FsPath.IsRecycleBin(userFileSystemNewPath) &&
                        !FsPath.AvoidSync(userFileSystemOldPath) && !FsPath.AvoidSync(userFileSystemNewPath))
                    {
                        inSync = PlaceholderItem.GetItem(userFileSystemOldPath).GetInSync();

                        string remoteStorageOldPath = Mapping.MapPath(userFileSystemOldPath);
                        string remoteStorageNewPath = Mapping.MapPath(userFileSystemNewPath);

                        FileSystemInfo remoteStorageOldItem = FsPath.GetFileSystemItem(remoteStorageOldPath);

                        if (remoteStorageOldItem is FileInfo)
                        {
                            (remoteStorageOldItem as FileInfo).MoveTo(remoteStorageNewPath);
                        }
                        else
                        {
                            (remoteStorageOldItem as DirectoryInfo).MoveTo(remoteStorageNewPath);
                        }
                        LogMessage("Moved succesefully:", remoteStorageOldPath, remoteStorageNewPath);
                    }
                }
                finally
                {
                    resultContext.ReturnConfirmationResult();

                    // 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.
                    if ((inSync != null) && PlaceholderItem.IsPlaceholder(userFileSystemNewPath))
                    {
                        PlaceholderItem.GetItem(userFileSystemNewPath).SetInSync(inSync.Value);
                    }
                }
            }
            catch (Exception ex)
            {
                // remove try-catch when error processing inside CloudProvider is fixed.
                LogError("Move failed:", $"From: {this.FullPath} to:{userFileSystemNewPath}", ex);
            }
            finally
            {
                Program.RemoteStorageMonitorInstance.Enabled = true;
            }
        }
コード例 #3
0
        /// <summary>
        /// Recursively updates and creates files and folders in 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 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);


            // Update and create files/folders in remote storage.
            userFileSystemChildren = Directory.EnumerateFileSystemEntries(userFileSystemFolderPath, "*");
            foreach (string userFileSystemPath in userFileSystemChildren)
            {
                try
                {
                    if (!FsPath.AvoidSync(userFileSystemPath))
                    {
                        if (PlaceholderItem.GetItem(userFileSystemPath).IsNew(virtualDrive))
                        {
                            // Create a file/folder in the remote storage.
                            FileSystemItemTypeEnum itemType = FsPath.GetItemType(userFileSystemPath);
                            await virtualDrive.GetRemoteStorageRawItem(userFileSystemPath, itemType, this).CreateAsync();
                        }
                        else if (!PlaceholderItem.GetItem(userFileSystemPath).IsMoved())
                        {
                            // Update file/folder in the remote storage. Unlock if auto-locked.
                            FileSystemItemTypeEnum itemType = FsPath.GetItemType(userFileSystemPath);
                            await virtualDrive.GetRemoteStorageRawItem(userFileSystemPath, itemType, this).UpdateAsync();
                        }
                    }
                }
                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);
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Sends contending to the remote storage if the item is modified.
        /// If Auto-locking is enabled, automatically locks the file if not locked. Unlocks the file after the update if auto-locked.
        /// </summary>
        public async Task UpdateAsync()
        {
            Lock fileLock = null;

            try
            {
                if (!PlaceholderItem.GetItem(userFileSystemPath).GetInSync())
                {
                    // Lock file if auto-locking is enabled.
                    if (Config.Settings.AutoLock)
                    {
                        // Get existing lock or create a new lock.
                        fileLock = await LockAsync(FileMode.OpenOrCreate, LockMode.Auto);
                    }

                    ServerLockInfo lockInfo = fileLock != null ? await fileLock.GetLockInfoAsync() : null;

                    // Update item in remote storage.
                    logger.LogMessage("Sending to remote storage", userFileSystemPath);
                    await CreateOrUpdateAsync(FileMode.Open, lockInfo);

                    //await new UserFileSystemRawItem(userFileSystemPath).ClearStateAsync();
                    logger.LogMessage("Sent to remote storage succesefully", userFileSystemPath);
                }

                // Unlock if auto-locked.
                if (await Lock.GetLockModeAsync(userFileSystemPath) == LockMode.Auto)
                {
                    if (fileLock == null)
                    {
                        // Get existing lock.
                        fileLock = await Lock.LockAsync(userFileSystemPath, FileMode.Open, LockMode.None, logger);
                    }
                    await UnlockAsync(fileLock);
                }
            }
            catch (ClientLockFailedException ex)
            {
                // Failed to lock file. Possibly blocked from another thread. This is a normal behaviour.
                logger.LogMessage(ex.Message, userFileSystemPath);
            }
            catch (Exception ex)
            {
                // Some error when locking, updating or unlocking occured.
                await new UserFileSystemRawItem(userFileSystemPath).SetUploadErrorStateAsync(ex);

                // Rethrow the exception preserving stack trace of the original exception.
                System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw();
            }
            finally
            {
                if (fileLock != null)
                {
                    fileLock.Dispose();
                }
            }
        }
コード例 #5
0
        /// <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);
                    }
                }
            }
        }
コード例 #6
0
        /// <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();
            }
        }
コード例 #7
0
        /// <summary>
        /// Compares user file system item and remote storage item. Returns true if items are equal. False - otherwise.
        /// </summary>
        /// <param name="remoteStorageItem">Remote storage item info.</param>
        /// <returns>Returns true user file system item and remote storage item are equal. False - otherwise.</returns>
        public async Task <bool> EqualsAsync(FileSystemInfo remoteStorageItem)
        {
            // Here you will typically compare file ETags.
            // For the sake of simplicity we just compare LastWriteTime.

            long remoteStorageETag = remoteStorageItem.LastWriteTime.ToBinary();

            // We store remote storage LastWriteTime inside custom data when creating and updating files/folders.
            byte[] userFileSystemItemCustomData = PlaceholderItem.GetItem(userFileSystemPath).GetCustomData();
            long   userFileSystemETag           = BitConverter.ToInt64(userFileSystemItemCustomData);

            return(remoteStorageETag == userFileSystemETag);
        }
コード例 #8
0
        /// <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);
        }
コード例 #9
0
        /// <inheritdoc/>
        public async Task CloseAsync(IOperationContext operationContext, IResultContext context)
        {
            // Here, if the file in the user file system is modified (not in-sync), you will send the file content,
            // creation time, modification time and attributes to the remote storage.
            // We also send ETag, to make sure the changes on the server, if any, are not overwritten.

            Logger.LogMessage("IFile.CloseAsync()", UserFileSystemPath);

            string userFileSystemFilePath = UserFileSystemPath;

            // In case the file is moved it does not exist in user file system when CloseAsync() is called.
            if (Engine.ChangesProcessingEnabled &&
                FsPath.Exists(userFileSystemFilePath) &&
                !FsPath.AvoidSync(userFileSystemFilePath))
            {
                // In case the file is overwritten it is converted to a regular file prior to CloseAsync().
                // we need to convert it back into file/folder placeholder.
                if (!PlaceholderItem.IsPlaceholder(userFileSystemFilePath))
                {
                    PlaceholderItem.ConvertToPlaceholder(userFileSystemFilePath, false);
                    Logger.LogMessage("Converted to placeholder", userFileSystemFilePath);
                }

                try
                {
                    if (PlaceholderItem.GetItem(userFileSystemFilePath).IsNew(VirtualDrive))
                    {
                        // Create new file in the remote storage.
                        await new RemoteStorageRawItem <IVirtualFile>(userFileSystemFilePath, VirtualDrive, Logger).CreateAsync();
                    }
                    else if (!PlaceholderItem.GetItem(userFileSystemFilePath).IsMoved())
                    {
                        // Send content to remote storage. Unlock if auto-locked.
                        await new RemoteStorageRawItem <IVirtualFile>(userFileSystemFilePath, VirtualDrive, Logger).UpdateAsync();
                    }
                }
                catch (IOException ex)
                {
                    // Either the file is already being synced in another thread or client or server file is blocked by concurrent process.
                    // This is a normal behaviour.
                    // The file must be synched by your synchronyzation service at a later time, when the file becomes available.
                    Logger.LogMessage("Failed to upload file. Possibly in use by an application or blocked for synchronization in another thread:", ex.Message);
                }
            }
        }
コード例 #10
0
        /// <inheritdoc/>
        public async Task CloseAsync(IOperationContext operationContext, IResultContext context)
        {
            // Here, if the file in user file system is modified (not in-sync), we send file content,
            // creation time, modification time and attributes to remote storage.
            // We also create new ETag, associate it with a file in user file system and send it to the server.

            LogMessage("IFile.CloseAsync()", this.FullPath);

            string userFileSystemFilePath = this.FullPath;

            // In case the file is moved it does not exist in user file system when Close() is called.
            if (!FsPath.Exists(userFileSystemFilePath) || FsPath.AvoidSync(userFileSystemFilePath))
            {
                return;
            }

            // In case the file is overwritten it is converted to a regular file prior to Close().
            // we need to convert it back into file/folder placeholder.
            if (!PlaceholderItem.IsPlaceholder(userFileSystemFilePath))
            {
                PlaceholderItem.ConvertToPlaceholder(userFileSystemFilePath, false);
                LogMessage("Converted to placeholder:", userFileSystemFilePath);
            }

            if (!PlaceholderItem.GetItem(userFileSystemFilePath).GetInSync())
            {
                LogMessage("Changed:", userFileSystemFilePath);

                string remoteStorageFilePath = Mapping.MapPath(userFileSystemFilePath);

                try
                {
                    await new RemoteStorageItem(remoteStorageFilePath).UpdateAsync(userFileSystemFilePath);
                    LogMessage("Updated succesefully:", remoteStorageFilePath);
                }
                catch (IOException ex)
                {
                    // Either the file is already being synced in another thread or client or server file is blocked by concurrent process.
                    // This is a normal behaviour.
                    // The file must be synched by your synchronyzation service at a later time, when the file becomes available.
                    LogMessage("Failed to upload file. Possibly in use by an application or blocked for synchronization in another thread:", ex.Message);
                }
            }
        }
コード例 #11
0
        /// <summary>
        /// Moves a file or folder placeholder in user file system.
        /// </summary>
        /// <param name="newUserFileSystemPath">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 MoveAsync(string newUserFileSystemPath)
        {
            // Windows 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.

            PlaceholderItem oldUserFileSystemItem = PlaceholderItem.GetItem(userFileSystemPath);

            if (oldUserFileSystemItem.GetInSync())
            {
                Directory.Move(userFileSystemPath, newUserFileSystemPath);

                // The file is marked as not in sync after move/rename. Marking it as in-sync.
                PlaceholderItem.GetItem(newUserFileSystemPath).SetInSync(true);
            }
            else
            {
                throw new IOException("File not in-sync.");
            }
        }
コード例 #12
0
        /// <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(IFileSystemItemMetadata itemInfo)
        {
            FileSystemItemMetadataExt itemInfoExt = itemInfo as FileSystemItemMetadataExt ?? throw new NotImplementedException($"{nameof(FileSystemItemMetadataExt)}");

            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.
                    await virtualDrive.Engine.ServerNotifications(userFileSystemPath).UpdateAsync(itemInfoExt);

                    // Set ETag.
                    await eTagManager.SetETagAsync(itemInfoExt.ETag);

                    // Clear icon.
                    //await ClearStateAsync();

                    // Set the read-only attribute and all custom columns data.
                    await SetLockedByAnotherUserAsync(itemInfoExt.LockedByAnotherUser);
                    await SetCustomColumnsDataAsync(itemInfoExt.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);
        }
コード例 #13
0
        //$>

        //$<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);
        }
コード例 #14
0
        /// <summary>
        /// Completes move. This method is called by the platform.
        /// To move item manually use the <see cref="MoveToAsync(string)"/> method instead.
        /// Sets In-Sync state based on file content changes,
        /// Updates OriginalPath so the file does not appear as moved.
        /// </summary>
        /// <returns></returns>
        internal async Task MoveToCompletionAsync()
        {
            string userFileSystemNewPath = userFileSystemPath;

            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);
                        // Restore In-sync state.

                        /*
                         * if (inSync != null)
                         * {
                         *  placeholderNew.SetInSync(inSync.Value);
                         * }
                         * else
                         */
                        if (((placeholderNew is PlaceholderFile) && ((PlaceholderFile)placeholderNew).GetFileDataSizeInfo().ModifiedDataSize == 0) ||
                            (placeholderNew is PlaceholderFolder))
                        {
                            logger.LogMessage("Setting In-Sync state", userFileSystemNewPath);
                            placeholderNew.SetInSync(true);
                        }
                    }
                }

                // Recursively restore OriginalPath and the 'locked' icon.
                await MoveToCompletionRecursiveAsync(userFileSystemNewPath);
            }
        }
コード例 #15
0
        /// <summary>
        /// Gets file system item info from the user file system item.
        /// Removes Pinned, Unpinned and Offline flags from attributes.
        /// </summary>
        /// <param name="userFileSystemItem">User file system item info.</param>
        /// <returns><see cref="FileSystemItemBasicInfo"/> object.</returns>
        private static IFileSystemItemBasicInfo GetBasicInfo(FileSystemInfo userFileSystemItem)
        {
            FileSystemItemBasicInfo itemInfo;

            if (userFileSystemItem is FileInfo)
            {
                itemInfo = new FileBasicInfo();
            }
            else
            {
                itemInfo = new FolderBasicInfo();
            }

            // Remove Pinned, unpinned and offline flags,
            // so they do not occasionally go into the remote storage.
            FileAttributes flags = userFileSystemItem.Attributes
                                   & (FileAttributes) ~FileAttributesExt.Pinned
                                   & (FileAttributes) ~FileAttributesExt.Unpinned
                                   & (FileAttributes) ~FileAttributesExt.Offline;

            itemInfo.Name           = userFileSystemItem.Name;
            itemInfo.Attributes     = flags;
            itemInfo.CreationTime   = userFileSystemItem.CreationTime;
            itemInfo.LastWriteTime  = userFileSystemItem.LastWriteTime;
            itemInfo.LastAccessTime = userFileSystemItem.LastAccessTime;
            itemInfo.ChangeTime     = userFileSystemItem.LastWriteTime;

            itemInfo.CustomData = PlaceholderItem.GetItem(userFileSystemItem.FullName).GetCustomData();

            if (userFileSystemItem is FileInfo)
            {
                ((FileBasicInfo)itemInfo).Length = ((FileInfo)userFileSystemItem).Length;
            }
            ;

            return(itemInfo);
        }
コード例 #16
0
        /// <summary>
        /// Gets file system item info from the user file system item.
        /// Removes Pinned, Unpinned and Offline flags from attributes.
        /// </summary>
        /// <param name="userFileSystemItem">User file system item info.</param>
        /// <returns>Object implementing <see cref="IFileSystemItemMetadata"/> interface.</returns>
        private static IFileSystemItemMetadata GetMetadata(FileSystemInfo userFileSystemItem)
        {
            FileSystemItemMetadataExt itemInfo;

            if (userFileSystemItem is FileInfo)
            {
                itemInfo = new FileMetadataExt();
            }
            else
            {
                itemInfo = new FolderMetadataExt();
            }

            // Remove Pinned, unpinned and offline flags,
            // so they are not sent to the remote storage by mistake.
            FileAttributes flags = userFileSystemItem.Attributes
                                   & (FileAttributes) ~FileAttributesExt.Pinned
                                   & (FileAttributes) ~FileAttributesExt.Unpinned
                                   & (FileAttributes) ~FileAttributesExt.Offline;

            itemInfo.Name           = userFileSystemItem.Name;
            itemInfo.Attributes     = flags;
            itemInfo.CreationTime   = userFileSystemItem.CreationTime;
            itemInfo.LastWriteTime  = userFileSystemItem.LastWriteTime;
            itemInfo.LastAccessTime = userFileSystemItem.LastAccessTime;
            itemInfo.ChangeTime     = userFileSystemItem.LastWriteTime;

            itemInfo.CustomData = PlaceholderItem.GetItem(userFileSystemItem.FullName).GetCustomData();

            if (userFileSystemItem is FileInfo)
            {
                ((FileMetadataExt)itemInfo).Length = ((FileInfo)userFileSystemItem).Length;
            }
            ;

            return(itemInfo);
        }
コード例 #17
0
        /// <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();
            }
        }
コード例 #18
0
        //$<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);
                }
            }
        }
コード例 #19
0
        /// <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);
                }
            }
        }
コード例 #20
0
        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();
            }
        }
コード例 #21
0
        /// <summary>
        /// Creates or updates the item in the remote storage.
        /// </summary>
        /// <param name="mode">
        /// Indicates if the file should created or updated.
        /// Supported modes are <see cref="FileMode.CreateNew"/> and <see cref="FileMode.Open"/>
        /// </param>
        /// <param name="lockInfo">Information about the lock. Pass null if the item is not locked.</param>
        private async Task CreateOrUpdateAsync(FileMode mode, ServerLockInfo lockInfo = null)
        {
            if ((mode != FileMode.CreateNew) && (mode != FileMode.Open))
            {
                throw new ArgumentOutOfRangeException("mode", $"Must be {FileMode.CreateNew} or {FileMode.Open}");
            }

            FileSystemInfo userFileSystemItem = FsPath.GetFileSystemItem(userFileSystemPath);

            using (WindowsFileSystemItem userFileSystemWinItem = WindowsFileSystemItem.OpenReadAttributes(userFileSystemPath, FileMode.Open, FileShare.Read))
            //await using (FileStream userFileSystemStream = userFileSystemFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                // Create the new file/folder in the remote storage only if the file/folder in the user file system was not moved.
                // If the file is moved in user file system, move must first be syched to remote storage.
                if ((mode == FileMode.CreateNew) && PlaceholderItem.GetItem(userFileSystemPath).IsMoved())
                {
                    string originalPath = PlaceholderItem.GetItem(userFileSystemPath).GetOriginalPath();
                    throw new ConflictException(Modified.Client, $"The item was moved. Original path: {originalPath}");
                }

                // Ensures LastWriteTimeUtc is in sync with file content after Open() was called.
                userFileSystemItem.Refresh();

                IFileSystemItemBasicInfo info = GetBasicInfo(userFileSystemItem);

                // Update remote storage file.
                FileStream userFileSystemStream = null;
                try
                {
                    string eTag = null;
                    if (FsPath.IsFile(userFileSystemPath))
                    {
                        // File is marked as not in-sync when updated OR moved.
                        // Opening a file for reading triggers hydration, make sure to open only if content is modified.
                        if (PlaceholderFile.GetFileDataSizeInfo(userFileSystemWinItem.SafeHandle).ModifiedDataSize > 0)
                        {
                            //userFileSystemStream = new FileStream(userFileSystemWinItem.SafeHandle, FileAccess.Read);
                            userFileSystemStream = ((FileInfo)userFileSystemItem).Open(FileMode.Open, FileAccess.Read, FileShare.Read);
                        }
                        if (mode == FileMode.CreateNew)
                        {
                            string      userFileSystemParentPath = Path.GetDirectoryName(userFileSystemPath);
                            IUserFolder userFolder = await virtualDrive.GetItemAsync <IUserFolder>(userFileSystemParentPath);

                            eTag = await userFolder.CreateFileAsync((IFileBasicInfo)info, userFileSystemStream);
                        }
                        else
                        {
                            IUserFile userFile = await virtualDrive.GetItemAsync <IUserFile>(userFileSystemPath);

                            eTag = await userFile.UpdateAsync((IFileBasicInfo)info, userFileSystemStream, lockInfo);
                        }
                    }
                    else
                    {
                        if (mode == FileMode.CreateNew)
                        {
                            string      userFileSystemParentPath = Path.GetDirectoryName(userFileSystemPath);
                            IUserFolder userFolder = await virtualDrive.GetItemAsync <IUserFolder>(userFileSystemParentPath);

                            eTag = await userFolder.CreateFolderAsync((IFolderBasicInfo)info);
                        }
                        else
                        {
                            IUserFolder userFolder = await virtualDrive.GetItemAsync <IUserFolder>(userFileSystemPath);

                            eTag = await userFolder.UpdateAsync((IFolderBasicInfo)info, lockInfo);
                        }
                    }
                    await ETag.SetETagAsync(userFileSystemPath, eTag);

                    if (mode == FileMode.CreateNew)
                    {
                        PlaceholderItem.GetItem(userFileSystemPath).SetOriginalPath(userFileSystemPath);
                    }
                }
                finally
                {
                    if (userFileSystemStream != null)
                    {
                        userFileSystemStream.Close();
                    }
                }

                PlaceholderItem.SetInSync(userFileSystemWinItem.SafeHandle, true);
            }
        }
コード例 #22
0
        /// <inheritdoc/>
        public async Task UpdateAsync()
        {
            // This protects from ocationally calling update on moved items.
            if (PlaceholderItem.GetItem(userFileSystemPath).IsMoved())
            {
                string originalPath = PlaceholderItem.GetItem(userFileSystemPath).GetOriginalPath();
                throw new ConflictException(Modified.Client, $"The item was moved. Original path: {originalPath}");
            }

            LockSync lockSync = null;

            try
            {
                if (!PlaceholderItem.GetItem(userFileSystemPath).GetInSync())
                {
                    // This will make sure only one thread can do the lock-update-unlock sequence.
                    lockSync = await lockManager.LockAsync();

                    IVirtualFileSystemItem userFileSystemItem = await GetItemAsync(userFileSystemPath);

                    ServerLockInfo lockInfo = null;
                    if (userFileSystemItem is IVirtualLock)
                    {
                        // Get lock info in case of manual lock or failed lock/update/unlock
                        if (await lockManager.IsLockedAsync())
                        {
                            lockInfo = await lockManager.GetLockInfoAsync();
                        }

                        // Lock file if auto-locking is enabled.
                        else if (virtualDrive.Settings.AutoLock)
                        {
                            // Lock file in remote storage.
                            lockInfo = await LockAsync(lockSync, LockMode.Auto);
                        }
                    }

                    // Update item in remote storage.
                    logger.LogMessage("Sending to remote storage", userFileSystemPath);
                    await CreateOrUpdateAsync(FileMode.Open, lockInfo);

                    //await new UserFileSystemRawItem(userFileSystemPath).ClearStateAsync();
                    logger.LogMessage("Sent to remote storage succesefully", userFileSystemPath);
                }

                // Unlock if auto-locked.
                if (await lockManager.GetLockModeAsync() == LockMode.Auto)
                {
                    // Required in case the file failed to unlock during previous update.
                    lockSync ??= await lockManager.LockAsync();

                    // Send unlock request to remote storage.
                    await UnlockAsync(lockSync);
                }
            }
            catch (ClientLockFailedException ex)
            {
                // Failed to lock file. Possibly blocked from another thread. This is a normal behaviour.
                logger.LogMessage(ex.Message, userFileSystemPath);
            }
            catch (Exception ex)
            {
                // Some error when locking, updating or unlocking occured.
                await userFileSystemRawItem.SetUploadErrorStateAsync(ex);

                // Rethrow the exception preserving stack trace of the original exception.
                System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw();
            }
            finally
            {
                if (lockSync != null)
                {
                    lockSync.Dispose();
                }
                // Do not delete lock-token and lock-mode files here, it is required if IUserLock
                // interfce is implemented and the file was locked manually.
            }
        }
コード例 #23
0
        /// <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);

            IVirtualFolder userFolder = await virtualDrive.GetItemAsync <IVirtualFolder>(userFileSystemFolderPath, this);

            IEnumerable <FileSystemItemMetadataExt> remoteStorageChildrenItems = await userFolder.EnumerateChildrenAsync("*");

            // Create new files/folders in the user file system.
            foreach (FileSystemItemMetadataExt 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.
                    if (!FsPath.AvoidSync(remoteStorageItem.Name) && !FsPath.AvoidSync(userFileSystemPath))
                    {
                        if (!FsPath.Exists(userFileSystemPath))
                        {
                            LogMessage($"Creating", userFileSystemPath);

                            await virtualDrive.GetUserFileSystemRawItem(userFileSystemFolderPath, this).CreateAsync(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);
                    FileSystemItemMetadataExt remoteStorageItem = remoteStorageChildrenItems.FirstOrDefault(x => x.Name.Equals(itemName, StringComparison.InvariantCultureIgnoreCase));


                    if (!FsPath.AvoidSync(userFileSystemPath))
                    {
                        UserFileSystemRawItem userFileSystemRawItem = virtualDrive.GetUserFileSystemRawItem(userFileSystemPath, this);
                        if (remoteStorageItem == null)
                        {
                            if (PlaceholderItem.GetItem(userFileSystemPath).GetInSync()
                                //&& !PlaceholderItem.GetItem(userFileSystemPath).IsNew(virtualDrive) // Extra check to protect from deletion files that were deleted becuse of incorrect folder merging operation.
                                )
                            {
                                // Delete the file/folder in user file system.
                                LogMessage("Deleting item", userFileSystemPath);
                                await userFileSystemRawItem.DeleteAsync();

                                LogMessage("Deleted succesefully", userFileSystemPath);
                            }
                        }
                        else
                        {
                            if (PlaceholderItem.GetItem(userFileSystemPath).GetInSync() &&
                                !await virtualDrive.GetETagManager(userFileSystemPath).ETagEqualsAsync(remoteStorageItem))
                            {
                                // User file system <- remote storage update.
                                LogMessage("Remote item modified", userFileSystemPath);
                                await userFileSystemRawItem.UpdateAsync(remoteStorageItem);

                                LogMessage("Updated succesefully", userFileSystemPath);
                            }

                            // Set the read-only attribute and all custom columns data.
                            if (PlaceholderItem.GetItem(userFileSystemPath).GetInSync())
                            {
                                await userFileSystemRawItem.SetLockedByAnotherUserAsync(remoteStorageItem.LockedByAnotherUser);

                                await userFileSystemRawItem.SetCustomColumnsDataAsync(remoteStorageItem.CustomProperties);
                            }

                            // Hydrate / dehydrate the file.
                            if (userFileSystemRawItem.HydrationRequired())
                            {
                                LogMessage("Hydrating", userFileSystemPath);
                                try
                                {
                                    new PlaceholderFile(userFileSystemPath).Hydrate(0, -1);
                                    LogMessage("Hydrated succesefully", userFileSystemPath);
                                }
                                catch (FileLoadException)
                                {
                                    // Typically this happens if another thread already hydrating the file.
                                    LogMessage("Failed to hydrate. The file is blocked.", userFileSystemPath);
                                }
                            }
                            else if (userFileSystemRawItem.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);
                }
            }
        }
コード例 #24
0
        /// <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);
                }
            }
        }