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); }
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)); } }
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)); }
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))); }
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); }
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); } }
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))); }
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); }
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)); } }
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)); } }
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)); } }
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)); } }