Пример #1
0
 private ISet <string> GetPathsUnderRecycleBin(IEnumerable <IStorageItemWithPath> source)
 {
     return(source.Select(item => item.Path).Where(path => recycleBinHelpers.IsPathUnderRecycleBin(path)).ToHashSet());
 }
Пример #2
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);
            }
        }
Пример #3
0
        public async Task <ReturnResult> DeleteItemsAsync(IEnumerable <IStorageItemWithPath> source, bool showDialog, bool permanently, bool registerHistory)
        {
            source = await source.ToListAsync();

            var returnStatus = ReturnResult.InProgress;

            var deleteFromRecycleBin = source.Select(item => item.Path).Any(path => recycleBinHelpers.IsPathUnderRecycleBin(path));
            var canBeSentToBin       = !deleteFromRecycleBin && await recycleBinHelpers.HasRecycleBin(source.FirstOrDefault()?.Path);

            if (((!permanently && !canBeSentToBin) || UserSettingsService.PreferencesSettingsService.ShowConfirmDeleteDialog) && showDialog) // Check if the setting to show a confirmation dialog is on
            {
                var incomingItems             = new List <BaseFileSystemDialogItemViewModel>();
                List <ShellFileItem> binItems = null;
                foreach (var src in source)
                {
                    if (recycleBinHelpers.IsPathUnderRecycleBin(src.Path))
                    {
                        binItems ??= await recycleBinHelpers.EnumerateRecycleBin();

                        if (!binItems.IsEmpty())                                                        // Might still be null because we're deserializing the list from Json
                        {
                            var matchingItem = binItems.FirstOrDefault(x => x.RecyclePath == src.Path); // Get original file name
                            incomingItems.Add(new FileSystemDialogDefaultItemViewModel()
                            {
                                SourcePath = src.Path, DisplayName = matchingItem?.FileName ?? src.Name
                            });
                        }
                    }
                    else
                    {
                        incomingItems.Add(new FileSystemDialogDefaultItemViewModel()
                        {
                            SourcePath = src.Path
                        });
                    }
                }

                var dialogViewModel = FileSystemDialogViewModel.GetDialogViewModel(
                    new() { IsInDeleteMode = true },
                    (canBeSentToBin ? permanently : true, canBeSentToBin),
                    FilesystemOperationType.Delete,
                    incomingItems,
                    new());

                var dialogService = Ioc.Default.GetRequiredService <IDialogService>();

                if (await dialogService.ShowDialogAsync(dialogViewModel) != DialogResult.Primary)
                {
                    return(ReturnResult.Cancelled); // Return if the result isn't delete
                }

                // Delete selected items if the result is Yes
                permanently = dialogViewModel.DeletePermanently;
            }

            // post the status banner
            var banner = PostBannerHelpers.PostBanner_Delete(source, returnStatus, permanently, false, 0);

            banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = returnStatus < ReturnResult.Failed ? e.ToStatus() : returnStatus;

            var token = banner.CancellationToken;

            var sw = new Stopwatch();

            sw.Start();

            IStorageHistory history = await filesystemOperations.DeleteItemsAsync((IList <IStorageItemWithPath>) source, banner.Progress, banner.ErrorCode, permanently, token);

            ((IProgress <float>)banner.Progress).Report(100.0f);
            await Task.Yield();

            if (!permanently && registerHistory)
            {
                App.HistoryWrapper.AddHistory(history);
            }
            var itemsDeleted = history?.Source.Count() ?? 0;

            source.ForEach(x => App.JumpList.RemoveFolder(x.Path)); // Remove items from jump list

            banner.Remove();
            sw.Stop();

            PostBannerHelpers.PostBanner_Delete(source, returnStatus, permanently, token.IsCancellationRequested, itemsDeleted);

            return(returnStatus);
        }
Пример #4
0
        public async Task <ReturnResult> DeleteItemAsync(IStorageItemWithPath source, bool showDialog, bool permanently, bool registerHistory)
        {
            PostedStatusBanner banner;
            bool deleteFromRecycleBin = recycleBinHelpers.IsPathUnderRecycleBin(source.Path);

            if (deleteFromRecycleBin)
            {
                permanently = true;
            }

            if (permanently)
            {
                banner = associatedInstance.StatusCenterActions.PostBanner(string.Empty,
                                                                           associatedInstance.FilesystemViewModel.WorkingDirectory,
                                                                           0,
                                                                           ReturnResult.InProgress,
                                                                           FileOperationType.Delete);
            }
            else
            {
                banner = associatedInstance.StatusCenterActions.PostBanner(string.Empty,
                                                                           associatedInstance.FilesystemViewModel.WorkingDirectory,
                                                                           0,
                                                                           ReturnResult.InProgress,
                                                                           FileOperationType.Recycle);
            }

            var returnStatus = ReturnResult.InProgress;

            banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus();

            if (App.AppSettings.ShowConfirmDeleteDialog && showDialog) // Check if the setting to show a confirmation dialog is on
            {
                List <FilesystemItemsOperationItemModel> incomingItems = new List <FilesystemItemsOperationItemModel>
                {
                    new FilesystemItemsOperationItemModel(FilesystemOperationType.Delete, source.Path ?? source.Item.Path, null)
                };

                FilesystemOperationDialog dialog = FilesystemOperationDialogViewModel.GetDialog(new FilesystemItemsOperationDataModel(
                                                                                                    FilesystemOperationType.Delete,
                                                                                                    false,
                                                                                                    !deleteFromRecycleBin ? permanently : deleteFromRecycleBin,
                                                                                                    !deleteFromRecycleBin,
                                                                                                    incomingItems,
                                                                                                    new List <FilesystemItemsOperationItemModel>()));

                ContentDialogResult result = await dialog.ShowAsync();

                if (result != ContentDialogResult.Primary)
                {
                    banner.Remove();
                    return(ReturnResult.Cancelled); // Return if the result isn't delete
                }

                // Delete selected item if the result is Yes
                permanently = dialog.ViewModel.PermanentlyDelete;
            }

            var sw = new Stopwatch();

            sw.Start();

            IStorageHistory history = await filesystemOperations.DeleteAsync(source, banner.Progress, banner.ErrorCode, permanently, cancellationToken);

            ((IProgress <float>)banner.Progress).Report(100.0f);

            if (!permanently && registerHistory)
            {
                App.HistoryWrapper.AddHistory(history);
            }

            banner.Remove();
            sw.Stop();

            PostBannerHelpers.PostBanner_Delete(returnStatus, permanently ? FileOperationType.Delete : FileOperationType.Recycle, sw, associatedInstance);

            return(returnStatus);
        }
Пример #5
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));
            }
        }
Пример #6
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(@"\\?\", StringComparison.Ordinal) || 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", StringComparison.Ordinal)))).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 => StorageHelpers.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.HResult != HResult.COPYENGINE_E_USER_CANCELLED && x.HResult != 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));
            }
        }
Пример #7
0
        public async Task <ReturnResult> DeleteItemsAsync(IEnumerable <IStorageItemWithPath> source, bool showDialog, bool permanently, bool registerHistory)
        {
            source = await source.ToListAsync();

            var returnStatus = ReturnResult.InProgress;

            var deleteFromRecycleBin = source.Select(item => item.Path).Any(path => recycleBinHelpers.IsPathUnderRecycleBin(path));
            var canBeSentToBin       = !deleteFromRecycleBin && await recycleBinHelpers.HasRecycleBin(source.FirstOrDefault()?.Path);

            if (((!permanently && !canBeSentToBin) || UserSettingsService.PreferencesSettingsService.ShowConfirmDeleteDialog) && showDialog) // Check if the setting to show a confirmation dialog is on
            {
                List <FilesystemItemsOperationItemModel> incomingItems = new List <FilesystemItemsOperationItemModel>();

                foreach (var src in source)
                {
                    if (recycleBinHelpers.IsPathUnderRecycleBin(src.Path))
                    {
                        var binItems     = associatedInstance.FilesystemViewModel.FilesAndFolders;
                        var matchingItem = binItems.FirstOrDefault(x => x.ItemPath == src.Path); // Get original file name
                        incomingItems.Add(new FilesystemItemsOperationItemModel(FilesystemOperationType.Delete, src.Path, null, matchingItem?.ItemName));
                    }
                    else
                    {
                        incomingItems.Add(new FilesystemItemsOperationItemModel(FilesystemOperationType.Delete, src.Path, null));
                    }
                }

                var dialog = FilesystemOperationDialogViewModel.GetDialog(new FilesystemItemsOperationDataModel(
                                                                              FilesystemOperationType.Delete,
                                                                              false,
                                                                              canBeSentToBin ? permanently : true,
                                                                              canBeSentToBin,
                                                                              incomingItems,
                                                                              new List <FilesystemItemsOperationItemModel>()));

                if (await dialog.TryShowAsync() != DialogResult.Primary)
                {
                    return(ReturnResult.Cancelled); // Return if the result isn't delete
                }

                // Delete selected items if the result is Yes
                permanently = dialog.ViewModel.PermanentlyDelete;
            }

            // post the status banner
            var banner = PostBannerHelpers.PostBanner_Delete(source, returnStatus, permanently, false, 0);

            banner.ErrorCode.ProgressChanged += (s, e) => returnStatus = e.ToStatus();

            var token = banner.CancellationToken;

            var sw = new Stopwatch();

            sw.Start();

            IStorageHistory history = await filesystemOperations.DeleteItemsAsync((IList <IStorageItemWithPath>) source, banner.Progress, banner.ErrorCode, permanently, token);

            ((IProgress <float>)banner.Progress).Report(100.0f);
            await Task.Yield();

            if (!permanently && registerHistory)
            {
                App.HistoryWrapper.AddHistory(history);
            }
            var itemsDeleted = history?.Source.Count() ?? 0;

            source.ForEach(x => App.JumpList.RemoveFolder(x.Path)); // Remove items from jump list

            banner.Remove();
            sw.Stop();

            PostBannerHelpers.PostBanner_Delete(source, returnStatus, permanently, token.IsCancellationRequested, itemsDeleted);

            return(returnStatus);
        }