Skip to content

Commit 1c6c934

Browse files
committed
Add error dialogs on NotFound and AlreadyExists. Retry with StorageApi on long paths
1 parent bd66ddc commit 1c6c934

File tree

2 files changed

+102
-4
lines changed

2 files changed

+102
-4
lines changed

src/Files.Uwp/Filesystem/FilesystemOperations/FilesystemOperations.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ await DialogDisplayHelper.ShowDialogAsync(
172172
ContentDialog dialog = new ContentDialog()
173173
{
174174
Title = "ErrorDialogThisActionCannotBeDone".GetLocalized(),
175-
Content = $"{"ErrorDialogTheDestinationFolder".GetLocalized()} ({destinationName}) {"ErrorDialogIsASubfolder".GetLocalized()} (sourceName)",
175+
Content = $"{"ErrorDialogTheDestinationFolder".GetLocalized()} ({destinationName}) {"ErrorDialogIsASubfolder".GetLocalized()} ({sourceName})",
176176
//PrimaryButtonText = "Skip".GetLocalized(),
177177
CloseButtonText = "Cancel".GetLocalized()
178178
};
@@ -358,7 +358,7 @@ await DialogDisplayHelper.ShowDialogAsync(
358358
ContentDialog dialog = new ContentDialog()
359359
{
360360
Title = "ErrorDialogThisActionCannotBeDone".GetLocalized(),
361-
Content = "ErrorDialogTheDestinationFolder".GetLocalized() + " (" + destinationName + ") " + "ErrorDialogIsASubfolder".GetLocalized() + " (" + sourceName + ")",
361+
Content = $"{"ErrorDialogTheDestinationFolder".GetLocalized()} ({destinationName}) {"ErrorDialogIsASubfolder".GetLocalized()} ({sourceName})",
362362
//PrimaryButtonText = "Skip".GetLocalized(),
363363
CloseButtonText = "Cancel".GetLocalized()
364364
};
@@ -789,7 +789,7 @@ await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(iFilePath)
789789
{
790790
await DialogDisplayHelper.ShowDialogAsync("AccessDenied".GetLocalized(), "AccessDeniedDeleteDialog/Text".GetLocalized());
791791
}
792-
else if (((FileSystemStatusCode)fsResult).HasFlag(FileSystemStatusCode.Unauthorized))
792+
else if (((FileSystemStatusCode)fsResult).HasFlag(FileSystemStatusCode.NotFound))
793793
{
794794
await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
795795
}

src/Files.Uwp/Filesystem/FilesystemOperations/ShellFilesystemOperations.cs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,25 @@ public async Task<IStorageHistory> CopyItemsAsync(IList<IStorageItemWithPath> so
166166
var lockingProcess = await WhoIsLockingAsync(failedSources.Select(x => x.HResult == HResult.COPYENGINE_E_SHARING_VIOLATION_SRC ? x.Source : x.Destination));
167167
await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), lockingProcess != null ? string.Join(Environment.NewLine, lockingProcess.Select(x => $"Name: {x.Name}, PID: {x.Pid}")) : "");
168168
}
169+
else if (copyResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong))
170+
{
171+
// Retry with StorageFile API
172+
var failedSources = copyResult.Items.Where(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong);
173+
var copyZip = sourceNoSkip.Zip(destinationNoSkip, (src, dest) => new { src, dest }).Zip(collisionsNoSkip, (z1, coll) => new { z1.src, z1.dest, coll });
174+
var sourceMatch = await failedSources.Select(x => copyZip.SingleOrDefault(s => s.src.Path.Equals(x.Source, StringComparison.OrdinalIgnoreCase))).Where(x => x != null).ToListAsync();
175+
return await filesystemOperations.CopyItemsAsync(
176+
await sourceMatch.Select(x => x.src).ToListAsync(),
177+
await sourceMatch.Select(x => x.dest).ToListAsync(),
178+
await sourceMatch.Select(x => x.coll).ToListAsync(), progress, errorCode, cancellationToken);
179+
}
180+
else if (copyResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NotFound))
181+
{
182+
await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
183+
}
184+
else if (copyResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.AlreadyExists))
185+
{
186+
await DialogDisplayHelper.ShowDialogAsync("ItemAlreadyExistsDialogTitle".GetLocalized(), "ItemAlreadyExistsDialogContent".GetLocalized());
187+
}
169188
errorCode?.Report(HResult.Convert(copyResult.Items.FirstOrDefault(x => !x.Succeeded)?.HResult));
170189
return null;
171190
}
@@ -254,6 +273,19 @@ public async Task<IStorageHistory> CopyItemsAsync(IList<IStorageItemWithPath> so
254273
return await CreateAsync(source, errorCode, cancellationToken);
255274
}
256275
}
276+
else if (createResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong))
277+
{
278+
// Retry with StorageFile API
279+
return await filesystemOperations.CreateAsync(source, errorCode, cancellationToken);
280+
}
281+
else if (createResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NotFound))
282+
{
283+
await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
284+
}
285+
else if (createResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.AlreadyExists))
286+
{
287+
await DialogDisplayHelper.ShowDialogAsync("ItemAlreadyExistsDialogTitle".GetLocalized(), "ItemAlreadyExistsDialogContent".GetLocalized());
288+
}
257289
errorCode?.Report(HResult.Convert(createResult.Items.FirstOrDefault(x => !x.Succeeded)?.HResult));
258290
return (null, null);
259291
}
@@ -397,6 +429,17 @@ public async Task<IStorageHistory> DeleteItemsAsync(IList<IStorageItemWithPath>
397429
var lockingProcess = await WhoIsLockingAsync(failedSources.Select(x => x.HResult == HResult.COPYENGINE_E_SHARING_VIOLATION_SRC ? x.Source : x.Destination));
398430
await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), lockingProcess != null ? string.Join(Environment.NewLine, lockingProcess.Select(x => $"Name: {x.Name}, PID: {x.Pid}")) : "");
399431
}
432+
else if (deleteResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong))
433+
{
434+
// Abort, path is too long for recycle bin
435+
//var failedSources = deleteResult.Items.Where(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong);
436+
//var sourceMatch = await failedSources.Select(x => source.DistinctBy(x => x.Path).SingleOrDefault(s => s.Path.Equals(x.Source, StringComparison.OrdinalIgnoreCase))).Where(x => x != null).ToListAsync();
437+
//return await filesystemOperations.DeleteItemsAsync(sourceMatch, progress, errorCode, permanently, cancellationToken);
438+
}
439+
else if (deleteResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NotFound))
440+
{
441+
await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
442+
}
400443
errorCode?.Report(HResult.Convert(deleteResult.Items.FirstOrDefault(x => !x.Succeeded)?.HResult));
401444
return null;
402445
}
@@ -515,13 +558,38 @@ public async Task<IStorageHistory> MoveItemsAsync(IList<IStorageItemWithPath> so
515558
return await MoveItemsAsync(source, destination, collisions, progress, errorCode, cancellationToken);
516559
}
517560
}
561+
else if (source.Zip(destination, (src, dest) => (src, dest)).FirstOrDefault(x => x.src.ItemType == FilesystemItemType.Directory && PathNormalization.GetParentDir(x.dest).IsSubPathOf(x.src.Path)) is (IStorageItemWithPath, string) subtree)
562+
{
563+
var destName = subtree.dest.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries).Last();
564+
var srcName = subtree.src.Path.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries).Last();
565+
await DialogDisplayHelper.ShowDialogAsync("ErrorDialogThisActionCannotBeDone".GetLocalized(), $"{"ErrorDialogTheDestinationFolder".GetLocalized()} ({destName}) {"ErrorDialogIsASubfolder".GetLocalized()} ({srcName})");
566+
}
518567
else if (moveResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.InUse))
519568
{
520569
// TODO: proper dialog, retry
521570
var failedSources = moveResult.Items.Where(x => HResult.Convert(x.HResult) == FileSystemStatusCode.InUse);
522571
var lockingProcess = await WhoIsLockingAsync(failedSources.Select(x => x.HResult == HResult.COPYENGINE_E_SHARING_VIOLATION_SRC ? x.Source : x.Destination));
523572
await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), lockingProcess != null ? string.Join(Environment.NewLine, lockingProcess.Select(x => $"Name: {x.Name}, PID: {x.Pid}")) : "");
524573
}
574+
else if (moveResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong))
575+
{
576+
// Retry with StorageFile API
577+
var failedSources = moveResult.Items.Where(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong);
578+
var moveZip = sourceNoSkip.Zip(destinationNoSkip, (src, dest) => new { src, dest }).Zip(collisionsNoSkip, (z1, coll) => new { z1.src, z1.dest, coll });
579+
var sourceMatch = await failedSources.Select(x => moveZip.SingleOrDefault(s => s.src.Path.Equals(x.Source, StringComparison.OrdinalIgnoreCase))).Where(x => x != null).ToListAsync();
580+
return await filesystemOperations.MoveItemsAsync(
581+
await sourceMatch.Select(x => x.src).ToListAsync(),
582+
await sourceMatch.Select(x => x.dest).ToListAsync(),
583+
await sourceMatch.Select(x => x.coll).ToListAsync(), progress, errorCode, cancellationToken);
584+
}
585+
else if (moveResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NotFound))
586+
{
587+
await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
588+
}
589+
else if (moveResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.AlreadyExists))
590+
{
591+
await DialogDisplayHelper.ShowDialogAsync("ItemAlreadyExistsDialogTitle".GetLocalized(), "ItemAlreadyExistsDialogContent".GetLocalized());
592+
}
525593
errorCode?.Report(HResult.Convert(moveResult.Items.FirstOrDefault(x => !x.Succeeded)?.HResult));
526594
return null;
527595
}
@@ -586,6 +654,19 @@ public async Task<IStorageHistory> RenameAsync(IStorageItemWithPath source, stri
586654
var lockingProcess = await WhoIsLockingAsync(failedSources.Select(x => x.HResult == HResult.COPYENGINE_E_SHARING_VIOLATION_SRC ? x.Source : x.Destination));
587655
await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), lockingProcess != null ? string.Join(Environment.NewLine, lockingProcess.Select(x => $"Name: {x.Name}, PID: {x.Pid}")) : "");
588656
}
657+
else if (renameResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong))
658+
{
659+
// Retry with StorageFile API
660+
return await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken);
661+
}
662+
else if (renameResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NotFound))
663+
{
664+
await DialogDisplayHelper.ShowDialogAsync("RenameError/ItemDeleted/Title".GetLocalized(), "RenameError/ItemDeleted/Text".GetLocalized());
665+
}
666+
else if (renameResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.AlreadyExists))
667+
{
668+
await DialogDisplayHelper.ShowDialogAsync("ItemAlreadyExistsDialogTitle".GetLocalized(), "ItemAlreadyExistsDialogContent".GetLocalized());
669+
}
589670
errorCode?.Report(HResult.Convert(renameResult.Items.FirstOrDefault(x => !x.Succeeded)?.HResult));
590671
return null;
591672
}
@@ -681,6 +762,24 @@ public async Task<IStorageHistory> RestoreItemsFromTrashAsync(IList<IStorageItem
681762
var lockingProcess = await WhoIsLockingAsync(failedSources.Select(x => x.HResult == HResult.COPYENGINE_E_SHARING_VIOLATION_SRC ? x.Source : x.Destination));
682763
await DialogDisplayHelper.ShowDialogAsync("FileInUseDeleteDialog/Title".GetLocalized(), lockingProcess != null ? string.Join(Environment.NewLine, lockingProcess.Select(x => $"Name: {x.Name}, PID: {x.Pid}")) : "");
683764
}
765+
else if (moveResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong))
766+
{
767+
// Retry with StorageFile API
768+
var failedSources = moveResult.Items.Where(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NameTooLong);
769+
var moveZip = source.Zip(destination, (src, dest) => new { src, dest });
770+
var sourceMatch = await failedSources.Select(x => moveZip.SingleOrDefault(s => s.src.Path.Equals(x.Source, StringComparison.OrdinalIgnoreCase))).Where(x => x != null).ToListAsync();
771+
return await filesystemOperations.RestoreItemsFromTrashAsync(
772+
await sourceMatch.Select(x => x.src).ToListAsync(),
773+
await sourceMatch.Select(x => x.dest).ToListAsync(), progress, errorCode, cancellationToken);
774+
}
775+
else if (moveResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.NotFound))
776+
{
777+
await DialogDisplayHelper.ShowDialogAsync("FileNotFoundDialog/Title".GetLocalized(), "FileNotFoundDialog/Text".GetLocalized());
778+
}
779+
else if (moveResult.Items.Any(x => HResult.Convert(x.HResult) == FileSystemStatusCode.AlreadyExists))
780+
{
781+
await DialogDisplayHelper.ShowDialogAsync("ItemAlreadyExistsDialogTitle".GetLocalized(), "ItemAlreadyExistsDialogContent".GetLocalized());
782+
}
684783
errorCode?.Report(HResult.Convert(moveResult.Items.FirstOrDefault(x => !x.Succeeded)?.HResult));
685784
return null;
686785
}
@@ -795,7 +894,6 @@ private struct HResult
795894
//public const int COPYENGINE_E_SAME_FILE = -2144927741;
796895
//public const int COPYENGINE_E_DEST_SAME_TREE = -2144927734;
797896
//public const int COPYENGINE_E_DEST_SUBTREE = -2144927735;
798-
//public const int COPYENGINE_E_DIFF_DIR = -2144927740;
799897

800898
public static FileSystemStatusCode Convert(int? hres)
801899
{

0 commit comments

Comments
 (0)