예제 #1
0
        /// <summary>
        /// Creates new file and folder placeholders in the user file system in this folder.
        /// </summary>
        /// <param name="newItemsInfo">Array of new files and folders.</param>
        /// <returns>Number of items created.</returns>
        public async Task <uint> CreateAsync(IFileSystemItemMetadata[] newItemsInfo)
        {
            string userFileSystemParentPath = userFileSystemPath;

            try
            {
                // Because of the on-demand population the file or folder placeholder may not exist in the user file system.
                // Here we also check that the folder content was loaded into user file system (the folder is not offline).
                if (Directory.Exists(userFileSystemParentPath) &&
                    !new DirectoryInfo(userFileSystemParentPath).Attributes.HasFlag(System.IO.FileAttributes.Offline))
                {
                    // Here we save current user file system path inside file/folder.
                    // If the file/folder is moved or renamed while this app is not running,
                    // we extract the saved path when this app starts and sync the file/folder to the remote storage.
                    foreach (var newItemInfo in newItemsInfo)
                    {
                        string userFileSystemPath = Path.Combine(userFileSystemParentPath, newItemInfo.Name);
                        newItemInfo.CustomData = new CustomData
                        {
                            OriginalPath = userFileSystemPath
                        }.Serialize();
                    }

                    // Create placeholders.
                    uint created = await virtualDrive.Engine.ServerNotifications(userFileSystemParentPath).CreateAsync(newItemsInfo);

                    // Create ETags.
                    foreach (IFileSystemItemMetadata newItemInfo in newItemsInfo)
                    {
                        FileSystemItemMetadataExt newItemInfoExt = newItemInfo as FileSystemItemMetadataExt ?? throw new NotImplementedException($"{nameof(FileSystemItemMetadataExt)}");

                        string userFileSystemNewItemPath = Path.Combine(userFileSystemParentPath, newItemInfoExt.Name);
                        await virtualDrive.GetETagManager(userFileSystemNewItemPath).SetETagAsync(newItemInfoExt.ETag);

                        // Set the read-only attribute and all custom columns data.
                        UserFileSystemRawItem newUserFileSystemRawItem = virtualDrive.GetUserFileSystemRawItem(userFileSystemNewItemPath, logger);
                        await newUserFileSystemRawItem.SetLockedByAnotherUserAsync(newItemInfoExt.LockedByAnotherUser);

                        await newUserFileSystemRawItem.SetCustomColumnsDataAsync(newItemInfoExt.CustomProperties);
                    }

                    return(created);
                }
            }
            catch (ExistsException ex)
            {
                // "Cannot create a file when that file already exists."
                //await new UserFileSystemItem(userFileSystemParentPath).ShowDownloadErrorAsync(ex);

                // Rethrow the exception preserving stack trace of the original exception.
                System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw();
            }

            return(0);
        }
예제 #2
0
        /// <summary>
        /// Creates instance of this class.
        /// </summary>
        /// <param name="userFileSystemPath">File or folder path in the user file system.</param>
        /// <param name="logger">Logger.</param>
        internal RemoteStorageRawItem(string userFileSystemPath, VirtualDriveBase virtualDrive, ILogger logger)
        {
            if (string.IsNullOrEmpty(userFileSystemPath))
            {
                throw new ArgumentNullException(nameof(userFileSystemPath));
            }

            this.virtualDrive = virtualDrive ?? throw new ArgumentNullException(nameof(virtualDrive));
            this.logger       = logger ?? throw new ArgumentNullException(nameof(logger));

            this.userFileSystemPath    = userFileSystemPath;
            this.lockManager           = virtualDrive.LockManager(userFileSystemPath, logger);
            this.userFileSystemRawItem = virtualDrive.GetUserFileSystemRawItem(userFileSystemPath, logger);
        }
        /// <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);
                }
            }
        }