Exemplo n.º 1
0
        public async Task <IStorageHistory> RenameAsync(IStorageItem source,
                                                        string newName,
                                                        NameCollisionOption collision,
                                                        IProgress <FilesystemErrorCode> errorCode,
                                                        CancellationToken cancellationToken)
        {
            if (Path.GetFileName(source.Path) == newName && collision == NameCollisionOption.FailIfExists)
            {
                errorCode?.Report(FilesystemErrorCode.ERROR_ALREADYEXIST);
                return(null);
            }

            if (!string.IsNullOrWhiteSpace(newName) &&
                !FilesystemHelpers.ContainsRestrictedCharacters(newName) &&
                !FilesystemHelpers.ContainsRestrictedFileName(newName))
            {
                try
                {
                    FilesystemItemType itemType       = source.IsOfType(StorageItemTypes.File) ? FilesystemItemType.File : FilesystemItemType.Directory;
                    string             originalSource = source.Path;
                    await source.RenameAsync(newName, collision);

                    errorCode?.Report(FilesystemErrorCode.ERROR_SUCCESS);
                    return(new StorageHistory(FileOperationType.Rename, StorageItemHelpers.FromPathAndType(originalSource, itemType), source.FromStorageItem()));
                }
                catch (Exception e)
                {
                    errorCode?.Report(FilesystemTasks.GetErrorCode(e));
                    return(null);
                }
            }

            return(null);
        }
Exemplo n.º 2
0
        public async Task <IStorageHistory> RestoreFromTrashAsync(IStorageItemWithPath source, string destination, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || string.IsNullOrWhiteSpace(source.Path) || source.Path.StartsWith(@"\\?\") || string.IsNullOrWhiteSpace(destination) || destination.StartsWith(@"\\?\"))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.RestoreFromTrashAsync(source, destination, progress, errorCode, cancellationToken));
            }

            var operationID = Guid.NewGuid().ToString();

            using var _ = cancellationToken.Register(CancelOperation, operationID, false);

            EventHandler <Dictionary <string, object> > handler = (s, e) => OnProgressUpdated(s, e, progress);

            connection.RequestReceived += handler;

            var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
            {
                { "Arguments", "FileOperation" },
                { "fileop", "MoveItem" },
                { "operationID", operationID },
                { "filepath", source.Path },
                { "destpath", destination },
                { "overwrite", false }
            });

            var result = (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                            response.Get("Success", false));

            if (connection != null)
            {
                connection.RequestReceived -= handler;
            }

            if (result)
            {
                progress?.Report(100.0f);
                var movedItems = JsonConvert.DeserializeObject <IEnumerable <string> >(response["MovedItems"] as string);
                errorCode?.Report(FileSystemStatusCode.Success);
                if (movedItems != null && movedItems.Count() == 1)
                {
                    // Recycle bin also stores a file starting with $I for each item
                    await DeleteAsync(StorageItemHelpers.FromPathAndType(
                                          Path.Combine(Path.GetDirectoryName(source.Path), Path.GetFileName(source.Path).Replace("$R", "$I")), source.ItemType),
                                      null, null, true, cancellationToken);

                    return(new StorageHistory(FileOperationType.Restore, source,
                                              StorageItemHelpers.FromPathAndType(movedItems.Single(), source.ItemType)));
                }
                return(null); // Cannot undo overwrite operation
            }
            else
            {
                // Retry failed operations
                return(await filesystemOperations.RestoreFromTrashAsync(source, destination, progress, errorCode, cancellationToken));
            }
        }
 public virtual async void DeleteItem(RoutedEventArgs e)
 {
     await FilesystemHelpers.DeleteItemsAsync(
         SlimContentPage.SelectedItems.Select((item) => StorageItemHelpers.FromPathAndType(
                                                  item.ItemPath,
                                                  item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)).ToList(),
         true, false, true);
 }
 public virtual async void RestoreItem(RoutedEventArgs e)
 {
     if (SlimContentPage.IsItemSelected)
     {
         foreach (ListedItem listedItem in SlimContentPage.SelectedItems)
         {
             if (listedItem is RecycleBinItem binItem)
             {
                 FilesystemItemType itemType = binItem.PrimaryItemAttribute == StorageItemTypes.Folder ? FilesystemItemType.Directory : FilesystemItemType.File;
                 await FilesystemHelpers.RestoreFromTrashAsync(StorageItemHelpers.FromPathAndType(
                                                                   (listedItem as RecycleBinItem).ItemPath,
                                                                   itemType), (listedItem as RecycleBinItem).ItemOriginalPath, true);
             }
         }
     }
 }
        public async Task <IStorageHistory> RenameAsync(IStorageItemWithPath source, string newName, NameCollisionOption collision, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || string.IsNullOrWhiteSpace(source.Path) || source.Path.StartsWith(@"\\?\") || FtpHelpers.IsFtpPath(source.Path))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken));
            }

            var renameResult = new ShellOperationResult();

            var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
            {
                { "Arguments", "FileOperation" },
                { "fileop", "RenameItem" },
                { "operationID", Guid.NewGuid().ToString() },
                { "filepath", source.Path },
                { "newName", newName },
                { "overwrite", collision == NameCollisionOption.ReplaceExisting }
            });

            var result = (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                            response.Get("Success", false));
            var shellOpResult = JsonConvert.DeserializeObject <ShellOperationResult>(response.Get("Result", ""));

            renameResult.Items.AddRange(shellOpResult?.Items ?? Enumerable.Empty <ShellOperationItemResult>());

            result &= (FilesystemResult)renameResult.Items.All(x => x.Succeeded);

            if (result)
            {
                errorCode?.Report(FileSystemStatusCode.Success);
                var renamedSources = renameResult.Items.Where(x => new[] { source }.Select(s => s.Path).Contains(x.Source)).Where(x => x.Succeeded && x.Destination != null && x.Source != x.Destination);
                if (renamedSources.Any())
                {
                    return(new StorageHistory(FileOperationType.Rename, source,
                                              StorageItemHelpers.FromPathAndType(renamedSources.Single().Destination, source.ItemType)));
                }
                return(null); // Cannot undo overwrite operation
            }
            else
            {
                // Retry failed operations
                return(await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken));
            }
        }
Exemplo n.º 6
0
        public async Task <IStorageHistory> RenameAsync(IStorageItemWithPath source, string newName, NameCollisionOption collision, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || string.IsNullOrWhiteSpace(source.Path) || source.Path.StartsWith(@"\\?\"))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken));
            }

            var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
            {
                { "Arguments", "FileOperation" },
                { "fileop", "RenameItem" },
                { "operationID", Guid.NewGuid().ToString() },
                { "filepath", source.Path },
                { "newName", newName },
                { "overwrite", collision == NameCollisionOption.ReplaceExisting }
            });

            var result = (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                            response.Get("Success", false));

            if (result)
            {
                var renamedItems = JsonConvert.DeserializeObject <IEnumerable <string> >(response["RenamedItems"] as string);
                errorCode?.Report(FileSystemStatusCode.Success);
                if (collision != NameCollisionOption.ReplaceExisting && renamedItems != null && renamedItems.Count() == 1)
                {
                    return(new StorageHistory(FileOperationType.Rename, source,
                                              StorageItemHelpers.FromPathAndType(renamedItems.Single(), source.ItemType)));
                }
                return(null); // Cannot undo overwrite operation
            }
            else
            {
                // Retry failed operations
                return(await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken));
            }
        }
        public async Task <IStorageHistory> CreateShortcutItemsAsync(IEnumerable <IStorageItemWithPath> source, IEnumerable <string> destination, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var createdSources     = new List <IStorageItemWithPath>();
            var createdDestination = new List <IStorageItemWithPath>();

            var connection = await AppServiceConnectionHelper.Instance;

            if (connection != null)
            {
                var items = source.Zip(destination, (src, dest) => new { src, dest }).Where(x => !string.IsNullOrEmpty(x.src.Path) && !string.IsNullOrEmpty(x.dest));
                for (int i = 0; i < items.Count(); i++)
                {
                    var value = new ValueSet()
                    {
                        { "Arguments", "FileOperation" },
                        { "fileop", "CreateLink" },
                        { "targetpath", items.ElementAt(i).src.Path },
                        { "arguments", "" },
                        { "workingdir", "" },
                        { "runasadmin", false },
                        { "filepath", items.ElementAt(i).dest }
                    };
                    var(status, response) = await connection.SendMessageForResponseAsync(value);

                    var success = status == AppServiceResponseStatus.Success && response.Get("Success", false);
                    if (success)
                    {
                        createdSources.Add(items.ElementAt(i).src);
                        createdDestination.Add(StorageItemHelpers.FromPathAndType(items.ElementAt(i).dest, FilesystemItemType.File));
                    }
                    progress?.Report(i / (float)source.Count() * 100.0f);
                }
            }

            errorCode?.Report(createdSources.Count() == source.Count() ? FileSystemStatusCode.Success : FileSystemStatusCode.Generic);
            return(new StorageHistory(FileOperationType.CreateLink, createdSources, createdDestination));
        }
Exemplo n.º 8
0
        public async Task <IStorageHistory> RestoreFromTrashAsync(IStorageItemWithPath source,
                                                                  string destination,
                                                                  IProgress <float> progress,
                                                                  IProgress <FilesystemErrorCode> errorCode,
                                                                  CancellationToken cancellationToken)
        {
            FilesystemResult fsResult = FilesystemErrorCode.ERROR_INPROGRESS;

            errorCode?.Report(fsResult);

            if (source.ItemType == FilesystemItemType.Directory)
            {
                FilesystemResult <StorageFolder> sourceFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(source.Path);

                FilesystemResult <StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));

                fsResult = sourceFolder.ErrorCode | destinationFolder.ErrorCode;
                errorCode?.Report(fsResult);

                if (fsResult)
                {
                    fsResult = await FilesystemTasks.Wrap(() =>
                    {
                        return(MoveDirectoryAsync(sourceFolder.Result,
                                                  destinationFolder.Result,
                                                  Path.GetFileName(destination),
                                                  CreationCollisionOption.FailIfExists));
                    }).OnSuccess(t => sourceFolder.Result.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask()); // TODO: we could use here FilesystemHelpers with registerHistory false?
                }
                errorCode?.Report(fsResult);
            }
            else
            {
                FilesystemResult <StorageFile> sourceFile = await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(source.Path);

                FilesystemResult <StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));

                fsResult = sourceFile.ErrorCode | destinationFolder.ErrorCode;
                errorCode?.Report(fsResult);

                if (fsResult)
                {
                    fsResult = await FilesystemTasks.Wrap(() =>
                    {
                        return(sourceFile.Result.MoveAsync(destinationFolder.Result,
                                                           Path.GetFileName(destination),
                                                           NameCollisionOption.GenerateUniqueName).AsTask());
                    });
                }
                else if (fsResult == FilesystemErrorCode.ERROR_UNAUTHORIZED)
                {
                    // Try again with MoveFileFromApp
                    fsResult = (FilesystemResult)NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination);
                }
                errorCode?.Report(fsResult);
            }

            if (fsResult)
            {
                // Recycle bin also stores a file starting with $I for each item
                string iFilePath = Path.Combine(Path.GetDirectoryName(source.Path), Path.GetFileName(source.Path).Replace("$R", "$I"));
                await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(iFilePath)
                .OnSuccess(iFile => iFile.DeleteAsync().AsTask());
            }

            errorCode?.Report(fsResult);
            if (fsResult != FilesystemErrorCode.ERROR_SUCCESS)
            {
                if (((FilesystemErrorCode)fsResult).HasFlag(FilesystemErrorCode.ERROR_UNAUTHORIZED))
                {
                    await DialogDisplayHelper.ShowDialogAsync("AccessDeniedDeleteDialog/Title".GetLocalized(), "AccessDeniedDeleteDialog/Text".GetLocalized());
                }
                else if (((FilesystemErrorCode)fsResult).HasFlag(FilesystemErrorCode.ERROR_UNAUTHORIZED))
                {
                    await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
                }
                else if (((FilesystemErrorCode)fsResult).HasFlag(FilesystemErrorCode.ERROR_ALREADYEXIST))
                {
                    await DialogDisplayHelper.ShowDialogAsync("ItemAlreadyExistsDialogTitle".GetLocalized(), "ItemAlreadyExistsDialogContent".GetLocalized());
                }
            }

            return(new StorageHistory(FileOperationType.Restore, source, StorageItemHelpers.FromPathAndType(destination, source.ItemType)));
        }
Exemplo n.º 9
0
        public async Task <IStorageHistory> RenameAsync(IStorageItemWithPath source,
                                                        string newName,
                                                        NameCollisionOption collision,
                                                        IProgress <FilesystemErrorCode> errorCode,
                                                        CancellationToken cancellationToken)
        {
            if (Path.GetFileName(source.Path) == newName && collision == NameCollisionOption.FailIfExists)
            {
                errorCode?.Report(FilesystemErrorCode.ERROR_ALREADYEXIST);
                return(null);
            }

            if (!string.IsNullOrWhiteSpace(newName) &&
                !FilesystemHelpers.ContainsRestrictedCharacters(newName) &&
                !FilesystemHelpers.ContainsRestrictedFileName(newName))
            {
                var renamed = await source.ToStorageItemResult(associatedInstance)
                              .OnSuccess(async(t) =>
                {
                    await t.RenameAsync(newName, collision);
                    return(t);
                });

                if (renamed)
                {
                    errorCode?.Report(FilesystemErrorCode.ERROR_SUCCESS);
                    return(new StorageHistory(FileOperationType.Rename, source, renamed.Result.FromStorageItem()));
                }
                else if (renamed == FilesystemErrorCode.ERROR_UNAUTHORIZED)
                {
                    // Try again with MoveFileFromApp
                    var destination = Path.Combine(Path.GetDirectoryName(source.Path), newName);
                    if (NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination))
                    {
                        errorCode?.Report(FilesystemErrorCode.ERROR_SUCCESS);
                        return(new StorageHistory(FileOperationType.Rename, source, StorageItemHelpers.FromPathAndType(destination, source.ItemType)));
                    }
                    else
                    {
                        Debug.WriteLine(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
                    }
                }
                else if (renamed == FilesystemErrorCode.ERROR_NOTAFILE || renamed == FilesystemErrorCode.ERROR_NOTAFOLDER)
                {
                    await DialogDisplayHelper.ShowDialogAsync("RenameError/NameInvalid/Title".GetLocalized(), "RenameError/NameInvalid/Text".GetLocalized());
                }
                else if (renamed == FilesystemErrorCode.ERROR_NAMETOOLONG)
                {
                    await DialogDisplayHelper.ShowDialogAsync("RenameError/TooLong/Title".GetLocalized(), "RenameError/TooLong/Text".GetLocalized());
                }
                else if (renamed == FilesystemErrorCode.ERROR_INUSE)
                {
                    // TODO: proper dialog, retry
                    await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), "");
                }
                else if (renamed == FilesystemErrorCode.ERROR_NOTFOUND)
                {
                    await DialogDisplayHelper.ShowDialogAsync("RenameError/ItemDeleted/Title".GetLocalized(), "RenameError/ItemDeleted/Text".GetLocalized());
                }
                else if (renamed == FilesystemErrorCode.ERROR_ALREADYEXIST)
                {
                    var ItemAlreadyExistsDialog = new ContentDialog()
                    {
                        Title               = "ItemAlreadyExistsDialogTitle".GetLocalized(),
                        Content             = "ItemAlreadyExistsDialogContent".GetLocalized(),
                        PrimaryButtonText   = "ItemAlreadyExistsDialogPrimaryButtonText".GetLocalized(),
                        SecondaryButtonText = "ItemAlreadyExistsDialogSecondaryButtonText".GetLocalized(),
                        CloseButtonText     = "ItemAlreadyExistsDialogCloseButtonText".GetLocalized()
                    };

                    ContentDialogResult result = await ItemAlreadyExistsDialog.ShowAsync();

                    if (result == ContentDialogResult.Primary)
                    {
                        return(await RenameAsync(source, newName, NameCollisionOption.GenerateUniqueName, errorCode, cancellationToken));
                    }
                    else if (result == ContentDialogResult.Secondary)
                    {
                        return(await RenameAsync(source, newName, NameCollisionOption.ReplaceExisting, errorCode, cancellationToken));
                    }
                }
                errorCode?.Report(renamed);
            }

            return(null);
        }
Exemplo n.º 10
0
        public async Task <IStorageHistory> DeleteAsync(IStorageItemWithPath source,
                                                        IProgress <float> progress,
                                                        IProgress <FilesystemErrorCode> errorCode,
                                                        bool permanently,
                                                        CancellationToken cancellationToken)
        {
            bool deleteFromRecycleBin = recycleBinHelpers.IsPathUnderRecycleBin(source.Path);

            FilesystemResult fsResult = FilesystemErrorCode.ERROR_INPROGRESS;

            errorCode?.Report(fsResult);
            progress?.Report(0.0f);

            if (source.ItemType == FilesystemItemType.File)
            {
                fsResult = await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(source.Path)
                           .OnSuccess((t) => t.DeleteAsync(permanently ? StorageDeleteOption.PermanentDelete : StorageDeleteOption.Default).AsTask());
            }
            else if (source.ItemType == FilesystemItemType.Directory)
            {
                fsResult = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(source.Path)
                           .OnSuccess((t) => t.DeleteAsync(permanently ? StorageDeleteOption.PermanentDelete : StorageDeleteOption.Default).AsTask());
            }

            errorCode?.Report(fsResult);

            if (fsResult == FilesystemErrorCode.ERROR_UNAUTHORIZED)
            {
                // Try again with fulltrust process
                if (associatedInstance.FilesystemViewModel.Connection != null)
                {
                    AppServiceResponse response = await associatedInstance.FilesystemViewModel.Connection.SendMessageAsync(new ValueSet()
                    {
                        { "Arguments", "FileOperation" },
                        { "fileop", "DeleteItem" },
                        { "filepath", source.Path },
                        { "permanently", permanently }
                    });

                    fsResult = (FilesystemResult)(response.Status == AppServiceResponseStatus.Success &&
                                                  response.Message.Get("Success", false));
                }
            }
            else if (fsResult == FilesystemErrorCode.ERROR_INUSE)
            {
                // TODO: retry or show dialog
                await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), "FileInUseDeleteDialog/Text".GetLocalized());
            }

            if (deleteFromRecycleBin)
            {
                // Recycle bin also stores a file starting with $I for each item
                string iFilePath = Path.Combine(Path.GetDirectoryName(source.Path), Path.GetFileName(source.Path).Replace("$R", "$I"));
                await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(iFilePath)
                .OnSuccess(t => t.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask());
            }
            errorCode?.Report(fsResult);
            progress?.Report(100.0f);

            if (fsResult)
            {
                await associatedInstance.FilesystemViewModel.RemoveFileOrFolderAsync(source.Path);

                if (!permanently)
                {
                    // Enumerate Recycle Bin
                    List <ShellFileItem> items = await recycleBinHelpers.EnumerateRecycleBin();

                    List <ShellFileItem> nameMatchItems = new List <ShellFileItem>();

                    // Get name matching files
                    if (items != null)
                    {
                        if (Path.GetExtension(source.Path) == ".lnk" || Path.GetExtension(source.Path) == ".url") // We need to check if it is a shortcut file
                        {
                            nameMatchItems = items.Where((item) => item.FilePath == Path.Combine(Path.GetDirectoryName(source.Path), Path.GetFileNameWithoutExtension(source.Path))).ToList();
                        }
                        else
                        {
                            nameMatchItems = items.Where((item) => item.FilePath == source.Path).ToList();
                        }
                    }

                    // Get newest file
                    ShellFileItem item = nameMatchItems.Where((item) => item.RecycleDate != null).OrderBy((item) => item.RecycleDate).FirstOrDefault();

                    return(new StorageHistory(FileOperationType.Recycle, source, StorageItemHelpers.FromPathAndType(item?.RecyclePath, source.ItemType)));
                }

                return(new StorageHistory(FileOperationType.Delete, source, null));
            }
            else
            {
                // Stop at first error
                return(null);
            }
        }
Exemplo n.º 11
0
        public async Task <IStorageHistory> RestoreFromTrashAsync(IStorageItemWithPath source,
                                                                  string destination,
                                                                  IProgress <float> progress,
                                                                  IProgress <FileSystemStatusCode> errorCode,
                                                                  CancellationToken cancellationToken)
        {
            FilesystemResult fsResult = FileSystemStatusCode.InProgress;

            errorCode?.Report(fsResult);

            fsResult = (FilesystemResult)await Task.Run(() => NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination));

            if (!fsResult)
            {
                if (source.ItemType == FilesystemItemType.Directory)
                {
                    FilesystemResult <StorageFolder> sourceFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(source.Path);

                    FilesystemResult <StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));

                    fsResult = sourceFolder.ErrorCode | destinationFolder.ErrorCode;
                    errorCode?.Report(fsResult);

                    if (fsResult)
                    {
                        fsResult = await FilesystemTasks.Wrap(() => MoveDirectoryAsync(sourceFolder.Result, destinationFolder.Result, Path.GetFileName(destination),
                                                                                       CreationCollisionOption.FailIfExists, true));

                        // TODO: we could use here FilesystemHelpers with registerHistory false?
                    }
                    errorCode?.Report(fsResult);
                }
                else
                {
                    FilesystemResult <StorageFile> sourceFile = await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(source.Path);

                    FilesystemResult <StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));

                    fsResult = sourceFile.ErrorCode | destinationFolder.ErrorCode;
                    errorCode?.Report(fsResult);

                    if (fsResult)
                    {
                        fsResult = await FilesystemTasks.Wrap(() => sourceFile.Result.MoveAsync(destinationFolder.Result, Path.GetFileName(destination), NameCollisionOption.GenerateUniqueName).AsTask());
                    }
                    errorCode?.Report(fsResult);
                }
                if (fsResult == FileSystemStatusCode.Unauthorized || fsResult == FileSystemStatusCode.ReadOnly)
                {
                    fsResult = await PerformAdminOperation(new ValueSet()
                    {
                        { "Arguments", "FileOperation" },
                        { "fileop", "MoveItem" },
                        { "filepath", source.Path },
                        { "destpath", destination },
                        { "overwrite", false }
                    });
                }
            }

            if (fsResult)
            {
                // Recycle bin also stores a file starting with $I for each item
                string iFilePath = Path.Combine(Path.GetDirectoryName(source.Path), Path.GetFileName(source.Path).Replace("$R", "$I"));
                await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(iFilePath)
                .OnSuccess(iFile => iFile.DeleteAsync().AsTask());
            }

            errorCode?.Report(fsResult);
            if (fsResult != FileSystemStatusCode.Success)
            {
                if (((FileSystemStatusCode)fsResult).HasFlag(FileSystemStatusCode.Unauthorized))
                {
                    await DialogDisplayHelper.ShowDialogAsync("AccessDeniedDeleteDialog/Title".GetLocalized(), "AccessDeniedDeleteDialog/Text".GetLocalized());
                }
                else if (((FileSystemStatusCode)fsResult).HasFlag(FileSystemStatusCode.Unauthorized))
                {
                    await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
                }
                else if (((FileSystemStatusCode)fsResult).HasFlag(FileSystemStatusCode.AlreadyExists))
                {
                    await DialogDisplayHelper.ShowDialogAsync("ItemAlreadyExistsDialogTitle".GetLocalized(), "ItemAlreadyExistsDialogContent".GetLocalized());
                }
            }

            return(new StorageHistory(FileOperationType.Restore, source, StorageItemHelpers.FromPathAndType(destination, source.ItemType)));
        }
Exemplo n.º 12
0
        public async Task <IStorageHistory> RenameAsync(IStorageItemWithPath source,
                                                        string newName,
                                                        NameCollisionOption collision,
                                                        IProgress <FileSystemStatusCode> errorCode,
                                                        CancellationToken cancellationToken)
        {
            if (Path.GetFileName(source.Path) == newName && collision == NameCollisionOption.FailIfExists)
            {
                errorCode?.Report(FileSystemStatusCode.AlreadyExists);
                return(null);
            }

            if (!string.IsNullOrWhiteSpace(newName) &&
                !FilesystemHelpers.ContainsRestrictedCharacters(newName) &&
                !FilesystemHelpers.ContainsRestrictedFileName(newName))
            {
                var renamed = await source.ToStorageItemResult(associatedInstance)
                              .OnSuccess(async(t) =>
                {
                    if (t.Name.Equals(newName, StringComparison.CurrentCultureIgnoreCase))
                    {
                        await t.RenameAsync(newName, NameCollisionOption.ReplaceExisting);
                    }
                    else
                    {
                        await t.RenameAsync(newName, collision);
                    }
                    return(t);
                });

                if (renamed)
                {
                    errorCode?.Report(FileSystemStatusCode.Success);
                    return(new StorageHistory(FileOperationType.Rename, source, renamed.Result.FromStorageItem()));
                }
                else if (renamed == FileSystemStatusCode.Unauthorized)
                {
                    // Try again with MoveFileFromApp
                    var destination = Path.Combine(Path.GetDirectoryName(source.Path), newName);
                    if (NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination))
                    {
                        errorCode?.Report(FileSystemStatusCode.Success);
                        return(new StorageHistory(FileOperationType.Rename, source, StorageItemHelpers.FromPathAndType(destination, source.ItemType)));
                    }
                    else
                    {
                        var fsResult = await PerformAdminOperation(new ValueSet()
                        {
                            { "Arguments", "FileOperation" },
                            { "fileop", "RenameItem" },
                            { "filepath", source.Path },
                            { "newName", newName },
                            { "overwrite", collision == NameCollisionOption.ReplaceExisting }
                        });

                        if (fsResult)
                        {
                            errorCode?.Report(FileSystemStatusCode.Success);
                            return(new StorageHistory(FileOperationType.Rename, source, StorageItemHelpers.FromPathAndType(destination, source.ItemType)));
                        }
                    }
                }
                else if (renamed == FileSystemStatusCode.NotAFile || renamed == FileSystemStatusCode.NotAFolder)
                {
                    await DialogDisplayHelper.ShowDialogAsync("RenameError/NameInvalid/Title".GetLocalized(), "RenameError/NameInvalid/Text".GetLocalized());
                }
                else if (renamed == FileSystemStatusCode.NameTooLong)
                {
                    await DialogDisplayHelper.ShowDialogAsync("RenameError/TooLong/Title".GetLocalized(), "RenameError/TooLong/Text".GetLocalized());
                }
                else if (renamed == FileSystemStatusCode.InUse)
                {
                    // TODO: proper dialog, retry
                    await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), "");
                }
                else if (renamed == FileSystemStatusCode.NotFound)
                {
                    await DialogDisplayHelper.ShowDialogAsync("RenameError/ItemDeleted/Title".GetLocalized(), "RenameError/ItemDeleted/Text".GetLocalized());
                }
                else if (renamed == FileSystemStatusCode.AlreadyExists)
                {
                    var ItemAlreadyExistsDialog = new ContentDialog()
                    {
                        Title               = "ItemAlreadyExistsDialogTitle".GetLocalized(),
                        Content             = "ItemAlreadyExistsDialogContent".GetLocalized(),
                        PrimaryButtonText   = "ItemAlreadyExistsDialogPrimaryButtonText".GetLocalized(),
                        SecondaryButtonText = "ItemAlreadyExistsDialogSecondaryButtonText".GetLocalized(),
                        CloseButtonText     = "ItemAlreadyExistsDialogCloseButtonText".GetLocalized()
                    };

                    if (UIHelpers.IsAnyContentDialogOpen())
                    {
                        // Only a single ContentDialog can be open at any time.
                        return(null);
                    }
                    ContentDialogResult result = await ItemAlreadyExistsDialog.ShowAsync();

                    if (result == ContentDialogResult.Primary)
                    {
                        return(await RenameAsync(source, newName, NameCollisionOption.GenerateUniqueName, errorCode, cancellationToken));
                    }
                    else if (result == ContentDialogResult.Secondary)
                    {
                        return(await RenameAsync(source, newName, NameCollisionOption.ReplaceExisting, errorCode, cancellationToken));
                    }
                }
                errorCode?.Report(renamed);
            }

            return(null);
        }
Exemplo n.º 13
0
        public async Task <IStorageHistory> CopyItemsAsync(IEnumerable <IStorageItemWithPath> source, IEnumerable <string> destination, IEnumerable <FileNameConflictResolveOptionType> collisions, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || source.Any(x => string.IsNullOrWhiteSpace(x.Path) || x.Path.StartsWith(@"\\?\")) || destination.Any(x => string.IsNullOrWhiteSpace(x) || x.StartsWith(@"\\?\")))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.CopyItemsAsync(source, destination, collisions, progress, errorCode, cancellationToken));
            }

            source      = source.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.Skip).ToList();
            destination = destination.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.Skip).ToList();
            collisions  = collisions.Where(c => c != FileNameConflictResolveOptionType.Skip).ToList();

            var operationID = Guid.NewGuid().ToString();

            using var _ = cancellationToken.Register(CancelOperation, operationID, false);

            EventHandler <Dictionary <string, object> > handler = (s, e) => OnProgressUpdated(s, e, progress);

            connection.RequestReceived += handler;

            var sourceReplace      = source.Where((src, index) => collisions.ElementAt(index) == FileNameConflictResolveOptionType.ReplaceExisting);
            var destinationReplace = destination.Where((src, index) => collisions.ElementAt(index) == FileNameConflictResolveOptionType.ReplaceExisting);
            var sourceRename       = source.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.ReplaceExisting);
            var destinationRename  = destination.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.ReplaceExisting);

            var result        = (FilesystemResult)true;
            var copiedItems   = new List <string>();
            var copiedSources = new List <string>();

            if (sourceRename.Any())
            {
                var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
                {
                    { "Arguments", "FileOperation" },
                    { "fileop", "CopyItem" },
                    { "operationID", operationID },
                    { "filepath", string.Join('|', sourceRename.Select(s => s.Path)) },
                    { "destpath", string.Join('|', destinationRename) },
                    { "overwrite", false }
                });

                result &= (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                             response.Get("Success", false));
                copiedItems.AddRange(JsonConvert.DeserializeObject <IEnumerable <string> >(response.Get("CopiedItems", "")) ?? Enumerable.Empty <string>());
                copiedSources.AddRange(JsonConvert.DeserializeObject <IEnumerable <string> >(response.Get("CopiedSources", "")) ?? Enumerable.Empty <string>());
            }
            if (sourceReplace.Any())
            {
                var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
                {
                    { "Arguments", "FileOperation" },
                    { "fileop", "CopyItem" },
                    { "operationID", operationID },
                    { "filepath", string.Join('|', sourceReplace.Select(s => s.Path)) },
                    { "destpath", string.Join('|', destinationReplace) },
                    { "overwrite", true }
                });

                result &= (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                             response.Get("Success", false));
                copiedSources.AddRange(JsonConvert.DeserializeObject <IEnumerable <string> >(response.Get("CopiedSources", "")) ?? Enumerable.Empty <string>());
            }

            if (connection != null)
            {
                connection.RequestReceived -= handler;
            }

            if (result)
            {
                progress?.Report(100.0f);
                errorCode?.Report(FileSystemStatusCode.Success);
                if (sourceRename.Any() && copiedItems.Count() == sourceRename.Count())
                {
                    return(new StorageHistory(FileOperationType.Copy, sourceRename,
                                              copiedItems.Select((item, index) => StorageItemHelpers.FromPathAndType(item, sourceRename.ElementAt(index).ItemType))));
                }
                return(null); // Cannot undo overwrite operation
            }
            else
            {
                // Retry failed operations
                var copiedZip = source.Zip(destination, (src, dest) => new { src, dest }).Zip(collisions, (z1, coll) => new { z1.src, z1.dest, coll }).Where(x => !copiedSources.Contains(x.src.Path));
                return(await filesystemOperations.CopyItemsAsync(copiedZip.Select(x => x.src), copiedZip.Select(x => x.dest), copiedZip.Select(x => x.coll), progress, errorCode, cancellationToken));
            }
        }
Exemplo n.º 14
0
        public async Task <IStorageHistory> DeleteItemsAsync(IEnumerable <IStorageItemWithPath> source, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, bool permanently, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || source.Any(x => string.IsNullOrWhiteSpace(x.Path) || x.Path.StartsWith(@"\\?\")))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.DeleteItemsAsync(source, progress, errorCode, permanently, cancellationToken));
            }

            var deleleFilePaths = source.Select(s => s.Path);

            var deleteFromRecycleBin = source.Any() ? recycleBinHelpers.IsPathUnderRecycleBin(source.ElementAt(0).Path) : false;

            permanently |= deleteFromRecycleBin;

            if (deleteFromRecycleBin)
            {
                // Recycle bin also stores a file starting with $I for each item
                deleleFilePaths = deleleFilePaths.Concat(source.Select(x => Path.Combine(Path.GetDirectoryName(x.Path), Path.GetFileName(x.Path).Replace("$R", "$I"))));
            }

            var operationID = Guid.NewGuid().ToString();

            using var _ = cancellationToken.Register(CancelOperation, operationID, false);

            EventHandler <Dictionary <string, object> > handler = (s, e) => OnProgressUpdated(s, e, progress);

            connection.RequestReceived += handler;

            var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
            {
                { "Arguments", "FileOperation" },
                { "fileop", "DeleteItem" },
                { "operationID", operationID },
                { "filepath", string.Join('|', deleleFilePaths) },
                { "permanently", permanently }
            });

            var result = (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                            response.Get("Success", false));

            if (connection != null)
            {
                connection.RequestReceived -= handler;
            }

            if (result)
            {
                progress?.Report(100.0f);
                var deletedItems  = JsonConvert.DeserializeObject <IEnumerable <string> >(response["DeletedItems"] as string);
                var recycledItems = JsonConvert.DeserializeObject <IEnumerable <string> >(response["RecycledItems"] as string);
                errorCode?.Report(FileSystemStatusCode.Success);
                if (deletedItems != null)
                {
                    foreach (var item in deletedItems)
                    {
                        await associatedInstance.FilesystemViewModel.RemoveFileOrFolderAsync(item);
                    }
                }
                if (!permanently && recycledItems != null && recycledItems.Count() == source.Count())
                {
                    return(new StorageHistory(FileOperationType.Recycle, source, recycledItems.Select((item, index) => StorageItemHelpers.FromPathAndType(item, source.ElementAt(index).ItemType))));
                }
                return(new StorageHistory(FileOperationType.Delete, source, null));
            }
            else
            {
                // Retry failed operations
                var deletedSources = JsonConvert.DeserializeObject <IEnumerable <string> >(response.Get("DeletedItems", "")) ?? Enumerable.Empty <string>();
                var deletedZip     = source.Where(x => !deletedSources.Contains(x.Path));
                return(await filesystemOperations.DeleteItemsAsync(deletedZip, progress, errorCode, permanently, cancellationToken));
            }
        }
Exemplo n.º 15
0
        public async Task <IStorageHistory> RestoreFromTrashAsync(IStorageItemWithPath source, string destination, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || string.IsNullOrWhiteSpace(source.Path) || source.Path.StartsWith(@"\\?\") || string.IsNullOrWhiteSpace(destination) || destination.StartsWith(@"\\?\") || FtpHelpers.IsFtpPath(destination))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.RestoreFromTrashAsync(source, destination, progress, errorCode, cancellationToken));
            }

            var operationID = Guid.NewGuid().ToString();

            using var r = cancellationToken.Register(CancelOperation, operationID, false);

            EventHandler <Dictionary <string, object> > handler = (s, e) => OnProgressUpdated(s, e, operationID, progress);

            connection.RequestReceived += handler;

            var moveResult = new ShellOperationResult();

            var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
            {
                { "Arguments", "FileOperation" },
                { "fileop", "MoveItem" },
                { "operationID", operationID },
                { "filepath", source.Path },
                { "destpath", destination },
                { "overwrite", false },
                { "HWND", NativeWinApiHelper.CoreWindowHandle.ToInt64() }
            });

            var result = (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                            response.Get("Success", false));
            var shellOpResult = JsonConvert.DeserializeObject <ShellOperationResult>(response.Get("Result", ""));

            moveResult.Items.AddRange(shellOpResult?.Items ?? Enumerable.Empty <ShellOperationItemResult>());

            if (connection != null)
            {
                connection.RequestReceived -= handler;
            }

            result &= (FilesystemResult)moveResult.Items.All(x => x.Succeeded);

            if (result)
            {
                progress?.Report(100.0f);
                errorCode?.Report(FileSystemStatusCode.Success);
                var movedSources = moveResult.Items.Where(x => new[] { source }.Select(s => s.Path).Contains(x.Source)).Where(x => x.Succeeded && x.Destination != null && x.Source != x.Destination);
                if (movedSources.Any())
                {
                    // Recycle bin also stores a file starting with $I for each item
                    await DeleteItemsAsync(movedSources.Select(src => StorageItemHelpers.FromPathAndType(
                                                                   Path.Combine(Path.GetDirectoryName(src.Source), Path.GetFileName(src.Source).Replace("$R", "$I")),
                                                                   new[] { source }.Single(s => s.Path == src.Source).ItemType)), null, null, true, cancellationToken);

                    return(new StorageHistory(FileOperationType.Restore, source,
                                              StorageItemHelpers.FromPathAndType(movedSources.Single().Destination, source.ItemType)));
                }
                return(null); // Cannot undo overwrite operation
            }
            else
            {
                // Retry failed operations
                return(await filesystemOperations.RestoreFromTrashAsync(source, destination, progress, errorCode, cancellationToken));
            }
        }
Exemplo n.º 16
0
        public async Task <IStorageHistory> DeleteItemsAsync(IEnumerable <IStorageItemWithPath> source, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, bool permanently, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || source.Any(x => string.IsNullOrWhiteSpace(x.Path) || x.Path.StartsWith(@"\\?\") || FtpHelpers.IsFtpPath(x.Path)))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.DeleteItemsAsync(source, progress, errorCode, permanently, cancellationToken));
            }

            source = source.DistinctBy(x => x.Path); // #5771
            var deleleFilePaths = source.Select(s => s.Path);

            var deleteFromRecycleBin = source.Any() ? recycleBinHelpers.IsPathUnderRecycleBin(source.ElementAt(0).Path) : false;

            permanently |= deleteFromRecycleBin;

            if (deleteFromRecycleBin)
            {
                // Recycle bin also stores a file starting with $I for each item
                deleleFilePaths = deleleFilePaths.Concat(source.Select(x => Path.Combine(Path.GetDirectoryName(x.Path), Path.GetFileName(x.Path).Replace("$R", "$I")))).Distinct();
            }

            var operationID = Guid.NewGuid().ToString();

            using var r = cancellationToken.Register(CancelOperation, operationID, false);

            EventHandler <Dictionary <string, object> > handler = (s, e) => OnProgressUpdated(s, e, operationID, progress);

            connection.RequestReceived += handler;

            var deleteResult = new ShellOperationResult();

            var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
            {
                { "Arguments", "FileOperation" },
                { "fileop", "DeleteItem" },
                { "operationID", operationID },
                { "filepath", string.Join('|', deleleFilePaths) },
                { "permanently", permanently },
                { "HWND", NativeWinApiHelper.CoreWindowHandle.ToInt64() }
            });

            var result = (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                            response.Get("Success", false));
            var shellOpResult = JsonConvert.DeserializeObject <ShellOperationResult>(response.Get("Result", ""));

            deleteResult.Items.AddRange(shellOpResult?.Items ?? Enumerable.Empty <ShellOperationItemResult>());

            if (connection != null)
            {
                connection.RequestReceived -= handler;
            }

            result &= (FilesystemResult)deleteResult.Items.All(x => x.Succeeded);

            if (result)
            {
                progress?.Report(100.0f);
                errorCode?.Report(FileSystemStatusCode.Success);
                foreach (var item in deleteResult.Items)
                {
                    await associatedInstance.FilesystemViewModel.RemoveFileOrFolderAsync(item.Source);
                }
                var recycledSources = deleteResult.Items.Where(x => source.Select(s => s.Path).Contains(x.Source)).Where(x => x.Succeeded && x.Destination != null && x.Source != x.Destination);
                if (recycledSources.Any())
                {
                    return(new StorageHistory(FileOperationType.Recycle, recycledSources.Select(x => source.Single(s => s.Path == x.Source)),
                                              recycledSources.Select(item => StorageItemHelpers.FromPathAndType(item.Destination, source.Single(s => s.Path == item.Source).ItemType))));
                }
                return(new StorageHistory(FileOperationType.Delete, source, null));
            }
            else
            {
                // Retry failed operations
                var failedSources = deleteResult.Items.Where(x => source.Select(s => s.Path).Contains(x.Source))
                                    .Where(x => !x.Succeeded && x.HRresult != HRESULT.COPYENGINE_E_USER_CANCELLED && x.HRresult != HRESULT.COPYENGINE_E_RECYCLE_BIN_NOT_FOUND);
                return(await filesystemOperations.DeleteItemsAsync(
                           failedSources.Select(x => source.Single(s => s.Path == x.Source)), progress, errorCode, permanently, cancellationToken));
            }
        }