コード例 #1
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();
            }
        }
コード例 #2
0
        private async Task CreateOrUpdateFileAsync(string userFileSystemPath, bool create)
        {
            try
            {
                Program.RemoteStorageMonitorInstance.Enabled = false; // Disable RemoteStorageMonitor to avoid circular calls.

                FileInfo userFileSystemFile = new FileInfo(userFileSystemPath);
                FileInfo remoteStorageFile  = new FileInfo(remoteStoragePath);

                FileMode fileMode = create ? FileMode.CreateNew : FileMode.Open;


                await using (FileStream userFileSystemStream = userFileSystemFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    // If another thread is trying to sync the same file, this call will fail in other threads.
                    // In your implemntation you must lock your remote storage file, or block it for reading and writing by other means.
                    await using (FileStream remoteStorageStream = remoteStorageFile.Open(fileMode, FileAccess.Write, FileShare.None))
                    {
                        userFileSystemFile.Refresh(); // Ensures LastWriteTimeUtc is in sync with file content after Open() was called.

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

                        // Update remote storage file content.
                        await userFileSystemStream.CopyToAsync(remoteStorageStream);

                        remoteStorageStream.SetLength(userFileSystemStream.Length);

                        // Update remote storage file basic info.
                        WindowsFileSystemItem.SetFileInformation(remoteStorageStream.SafeFileHandle,
                                                                 userFileSystemFile.Attributes & (FileAttributes) ~FileAttributesExt.Pinned, // Remove Pinned flag.
                                                                 userFileSystemFile.CreationTimeUtc,
                                                                 userFileSystemFile.LastWriteTimeUtc,
                                                                 userFileSystemFile.LastAccessTimeUtc,
                                                                 userFileSystemFile.LastWriteTimeUtc);

                        // If you are using ETags, here you will also send to the remote storage a new file ETag.

                        PlaceholderItem.SetInSync(userFileSystemStream.SafeFileHandle, true);
                    }
                }
            }
            finally
            {
                Program.RemoteStorageMonitorInstance.Enabled = true;
            }
        }
コード例 #3
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);
        }
コード例 #4
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);
            }
        }
コード例 #5
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();
            }
        }
コード例 #6
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);
            }
        }