Skip to content

Commit a3ee462

Browse files
committed
Merge remote-tracking branch 'origin/main' into remove_cache
2 parents 03fe656 + de5dd1b commit a3ee462

35 files changed

+823
-416
lines changed

Files.Launcher/Program.cs

+56
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,62 @@ await Win32API.StartSTATask(() =>
880880
}
881881
break;
882882

883+
case "RenameItem":
884+
var fileToRenamePath = (string)message["filepath"];
885+
var newName = (string)message["newName"];
886+
var overwriteOnRename = (bool)message["overwrite"];
887+
using (var op = new ShellFileOperations())
888+
{
889+
op.Options = ShellFileOperations.OperationFlags.NoUI;
890+
op.Options |= !overwriteOnRename ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision : 0;
891+
using var shi = new ShellItem(fileToRenamePath);
892+
op.QueueRenameOperation(shi, newName);
893+
var renameTcs = new TaskCompletionSource<bool>();
894+
op.PostRenameItem += (s, e) => renameTcs.TrySetResult(e.Result.Succeeded);
895+
op.PerformOperations();
896+
var result = await renameTcs.Task;
897+
await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", result } }, message.Get("RequestID", (string)null));
898+
}
899+
break;
900+
901+
case "MoveItem":
902+
var fileToMovePath = (string)message["filepath"];
903+
var moveDestination = (string)message["destpath"];
904+
var overwriteOnMove = (bool)message["overwrite"];
905+
using (var op = new ShellFileOperations())
906+
{
907+
op.Options = ShellFileOperations.OperationFlags.NoUI;
908+
op.Options |= !overwriteOnMove ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision : 0;
909+
using var shi = new ShellItem(fileToMovePath);
910+
using var shd = new ShellFolder(Path.GetDirectoryName(moveDestination));
911+
op.QueueMoveOperation(shi, shd, Path.GetFileName(moveDestination));
912+
var moveTcs = new TaskCompletionSource<bool>();
913+
op.PostMoveItem += (s, e) => moveTcs.TrySetResult(e.Result.Succeeded);
914+
op.PerformOperations();
915+
var result = await moveTcs.Task;
916+
await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", result } }, message.Get("RequestID", (string)null));
917+
}
918+
break;
919+
920+
case "CopyItem":
921+
var fileToCopyPath = (string)message["filepath"];
922+
var copyDestination = (string)message["destpath"];
923+
var overwriteOnCopy = (bool)message["overwrite"];
924+
using (var op = new ShellFileOperations())
925+
{
926+
op.Options = ShellFileOperations.OperationFlags.NoUI;
927+
op.Options |= !overwriteOnCopy ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision : 0;
928+
using var shi = new ShellItem(fileToCopyPath);
929+
using var shd = new ShellFolder(Path.GetDirectoryName(copyDestination));
930+
op.QueueCopyOperation(shi, shd, Path.GetFileName(copyDestination));
931+
var copyTcs = new TaskCompletionSource<bool>();
932+
op.PostCopyItem += (s, e) => copyTcs.TrySetResult(e.Result.Succeeded);
933+
op.PerformOperations();
934+
var result = await copyTcs.Task;
935+
await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", result } }, message.Get("RequestID", (string)null));
936+
}
937+
break;
938+
883939
case "ParseLink":
884940
var linkPath = (string)message["filepath"];
885941
try

Files/Enums/FileSystemStatusCode.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public enum FileSystemStatusCode
1414
AlreadyExists = 32,
1515
NotAFolder = 64,
1616
NotAFile = 128,
17-
InProgress = 256
17+
ReadOnly = 256,
18+
InProgress = 512
1819
}
1920
}

Files/Filesystem/FilesystemOperations/FilesystemOperations.cs

+119-56
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,17 @@ await DialogDisplayHelper.ShowDialogAsync(
197197
}
198198
fsResult = fsCopyResult;
199199
}
200+
if (fsResult == FileSystemStatusCode.Unauthorized)
201+
{
202+
fsResult = await PerformAdminOperation(new ValueSet()
203+
{
204+
{ "Arguments", "FileOperation" },
205+
{ "fileop", "CopyItem" },
206+
{ "filepath", source.Path },
207+
{ "destpath", destination },
208+
{ "overwrite", collision == NameCollisionOption.ReplaceExisting }
209+
});
210+
}
200211
errorCode?.Report(fsResult.ErrorCode);
201212
if (!fsResult)
202213
{
@@ -234,6 +245,17 @@ await DialogDisplayHelper.ShowDialogAsync(
234245
}
235246
fsResult = fsResultCopy;
236247
}
248+
if (fsResult == FileSystemStatusCode.Unauthorized)
249+
{
250+
fsResult = await PerformAdminOperation(new ValueSet()
251+
{
252+
{ "Arguments", "FileOperation" },
253+
{ "fileop", "CopyItem" },
254+
{ "filepath", source.Path },
255+
{ "destpath", destination },
256+
{ "overwrite", collision == NameCollisionOption.ReplaceExisting }
257+
});
258+
}
237259
}
238260
errorCode?.Report(fsResult.ErrorCode);
239261
if (!fsResult)
@@ -387,6 +409,17 @@ await DialogDisplayHelper.ShowDialogAsync(
387409
}
388410
fsResult = fsResultMove;
389411
}
412+
if (fsResult == FileSystemStatusCode.Unauthorized || fsResult == FileSystemStatusCode.ReadOnly)
413+
{
414+
fsResult = await PerformAdminOperation(new ValueSet()
415+
{
416+
{ "Arguments", "FileOperation" },
417+
{ "fileop", "MoveItem" },
418+
{ "filepath", source.Path },
419+
{ "destpath", destination },
420+
{ "overwrite", collision == NameCollisionOption.ReplaceExisting }
421+
});
422+
}
390423
}
391424
errorCode?.Report(fsResult.ErrorCode);
392425
}
@@ -406,7 +439,7 @@ await DialogDisplayHelper.ShowDialogAsync(
406439
if (fsResult)
407440
{
408441
var file = (StorageFile)sourceResult;
409-
var fsResultMove = await FilesystemTasks.Wrap(() => file.MoveAsync(destinationResult.Result, Path.GetFileName(file.Name), NameCollisionOption.FailIfExists).AsTask());
442+
var fsResultMove = await FilesystemTasks.Wrap(() => file.MoveAsync(destinationResult.Result, Path.GetFileName(file.Name), collision).AsTask());
410443

411444
if (fsResultMove == FileSystemStatusCode.AlreadyExists)
412445
{
@@ -421,6 +454,17 @@ await DialogDisplayHelper.ShowDialogAsync(
421454
}
422455
fsResult = fsResultMove;
423456
}
457+
if (fsResult == FileSystemStatusCode.Unauthorized || fsResult == FileSystemStatusCode.ReadOnly)
458+
{
459+
fsResult = await PerformAdminOperation(new ValueSet()
460+
{
461+
{ "Arguments", "FileOperation" },
462+
{ "fileop", "MoveItem" },
463+
{ "filepath", source.Path },
464+
{ "destpath", destination },
465+
{ "overwrite", collision == NameCollisionOption.ReplaceExisting }
466+
});
467+
}
424468
}
425469
errorCode?.Report(fsResult.ErrorCode);
426470
}
@@ -516,28 +560,13 @@ public async Task<IStorageHistory> DeleteAsync(IStorageItemWithPath source,
516560
}
517561
if (!fsResult)
518562
{
519-
var elevateConfirmDialog = new Files.Dialogs.ElevateConfirmDialog();
520-
var elevateConfirmResult = await elevateConfirmDialog.ShowAsync();
521-
if (elevateConfirmResult == ContentDialogResult.Primary)
563+
fsResult = await PerformAdminOperation(new ValueSet()
522564
{
523-
if (associatedInstance.ServiceConnection != null
524-
&& await associatedInstance.ServiceConnection.Elevate())
525-
{
526-
// Try again with fulltrust process (admin)
527-
if (associatedInstance.ServiceConnection != null)
528-
{
529-
var (status, response) = await associatedInstance.ServiceConnection.SendMessageForResponseAsync(new ValueSet()
530-
{
531-
{ "Arguments", "FileOperation" },
532-
{ "fileop", "DeleteItem" },
533-
{ "filepath", source.Path },
534-
{ "permanently", permanently }
535-
});
536-
fsResult = (FilesystemResult)(status == AppServiceResponseStatus.Success
537-
&& response.Get("Success", false));
538-
}
539-
}
540-
}
565+
{ "Arguments", "FileOperation" },
566+
{ "fileop", "DeleteItem" },
567+
{ "filepath", source.Path },
568+
{ "permanently", permanently }
569+
});
541570
}
542571
}
543572
else if (fsResult == FileSystemStatusCode.InUse)
@@ -649,7 +678,19 @@ public async Task<IStorageHistory> RenameAsync(IStorageItemWithPath source,
649678
}
650679
else
651680
{
652-
Debug.WriteLine(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
681+
var fsResult = await PerformAdminOperation(new ValueSet()
682+
{
683+
{ "Arguments", "FileOperation" },
684+
{ "fileop", "RenameItem" },
685+
{ "filepath", source.Path },
686+
{ "newName", newName },
687+
{ "overwrite", collision == NameCollisionOption.ReplaceExisting }
688+
});
689+
if (fsResult)
690+
{
691+
errorCode?.Report(FileSystemStatusCode.Success);
692+
return new StorageHistory(FileOperationType.Rename, source, StorageItemHelpers.FromPathAndType(destination, source.ItemType));
693+
}
653694
}
654695
}
655696
else if (renamed == FileSystemStatusCode.NotAFile || renamed == FileSystemStatusCode.NotAFolder)
@@ -711,50 +752,51 @@ public async Task<IStorageHistory> RestoreFromTrashAsync(IStorageItemWithPath so
711752
FilesystemResult fsResult = FileSystemStatusCode.InProgress;
712753
errorCode?.Report(fsResult);
713754

714-
if (source.ItemType == FilesystemItemType.Directory)
755+
fsResult = (FilesystemResult)await Task.Run(() => NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination));
756+
757+
if (!fsResult)
715758
{
716-
FilesystemResult<StorageFolder> sourceFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(source.Path);
717-
FilesystemResult<StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));
759+
if (source.ItemType == FilesystemItemType.Directory)
760+
{
761+
FilesystemResult<StorageFolder> sourceFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(source.Path);
762+
FilesystemResult<StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));
718763

719-
fsResult = sourceFolder.ErrorCode | destinationFolder.ErrorCode;
720-
errorCode?.Report(fsResult);
764+
fsResult = sourceFolder.ErrorCode | destinationFolder.ErrorCode;
765+
errorCode?.Report(fsResult);
721766

722-
if (fsResult)
723-
{
724-
fsResult = await FilesystemTasks.Wrap(() =>
767+
if (fsResult)
725768
{
726-
return MoveDirectoryAsync(sourceFolder.Result,
727-
destinationFolder.Result,
728-
Path.GetFileName(destination),
729-
CreationCollisionOption.FailIfExists,
730-
true);
731-
}); // TODO: we could use here FilesystemHelpers with registerHistory false?
769+
fsResult = await FilesystemTasks.Wrap(() => MoveDirectoryAsync(sourceFolder.Result, destinationFolder.Result, Path.GetFileName(destination),
770+
CreationCollisionOption.FailIfExists, true));
771+
// TODO: we could use here FilesystemHelpers with registerHistory false?
772+
}
773+
errorCode?.Report(fsResult);
732774
}
733-
errorCode?.Report(fsResult);
734-
}
735-
else
736-
{
737-
FilesystemResult<StorageFile> sourceFile = await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(source.Path);
738-
FilesystemResult<StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));
775+
else
776+
{
777+
FilesystemResult<StorageFile> sourceFile = await associatedInstance.FilesystemViewModel.GetFileFromPathAsync(source.Path);
778+
FilesystemResult<StorageFolder> destinationFolder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(Path.GetDirectoryName(destination));
739779

740-
fsResult = sourceFile.ErrorCode | destinationFolder.ErrorCode;
741-
errorCode?.Report(fsResult);
780+
fsResult = sourceFile.ErrorCode | destinationFolder.ErrorCode;
781+
errorCode?.Report(fsResult);
742782

743-
if (fsResult)
744-
{
745-
fsResult = await FilesystemTasks.Wrap(() =>
783+
if (fsResult)
746784
{
747-
return sourceFile.Result.MoveAsync(destinationFolder.Result,
748-
Path.GetFileName(destination),
749-
NameCollisionOption.GenerateUniqueName).AsTask();
750-
});
785+
fsResult = await FilesystemTasks.Wrap(() => sourceFile.Result.MoveAsync(destinationFolder.Result, Path.GetFileName(destination), NameCollisionOption.GenerateUniqueName).AsTask());
786+
}
787+
errorCode?.Report(fsResult);
751788
}
752-
else if (fsResult == FileSystemStatusCode.Unauthorized)
789+
if (fsResult == FileSystemStatusCode.Unauthorized || fsResult == FileSystemStatusCode.ReadOnly)
753790
{
754-
// Try again with MoveFileFromApp
755-
fsResult = (FilesystemResult)NativeFileOperationsHelper.MoveFileFromApp(source.Path, destination);
791+
fsResult = await PerformAdminOperation(new ValueSet()
792+
{
793+
{ "Arguments", "FileOperation" },
794+
{ "fileop", "MoveItem" },
795+
{ "filepath", source.Path },
796+
{ "destpath", destination },
797+
{ "overwrite", false }
798+
});
756799
}
757-
errorCode?.Report(fsResult);
758800
}
759801

760802
if (fsResult)
@@ -832,6 +874,27 @@ private static async Task<StorageFolder> MoveDirectoryAsync(IStorageFolder sourc
832874
return createdRoot;
833875
}
834876

877+
private async Task<FilesystemResult> PerformAdminOperation(ValueSet operation)
878+
{
879+
var elevateConfirmDialog = new Files.Dialogs.ElevateConfirmDialog();
880+
var elevateConfirmResult = await elevateConfirmDialog.ShowAsync();
881+
if (elevateConfirmResult == ContentDialogResult.Primary)
882+
{
883+
if (associatedInstance.ServiceConnection != null &&
884+
await associatedInstance.ServiceConnection.Elevate())
885+
{
886+
// Try again with fulltrust process (admin)
887+
if (associatedInstance.ServiceConnection != null)
888+
{
889+
var (status, response) = await associatedInstance.ServiceConnection.SendMessageForResponseAsync(operation);
890+
return (FilesystemResult)(status == AppServiceResponseStatus.Success
891+
&& response.Get("Success", false));
892+
}
893+
}
894+
}
895+
return (FilesystemResult)false;
896+
}
897+
835898
#endregion Helpers
836899

837900
#region IDisposable

Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs

+3-6
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ public async Task<ReturnResult> PerformOperationTypeAsync(DataPackageOperation o
404404
var items = await packageView.GetStorageItemsAsync();
405405
NavigationHelpers.OpenItemsWithExecutable(associatedInstance, items.ToList(), destination);
406406
}
407-
407+
408408
// TODO: Support link creation
409409
return default;
410410
}
@@ -861,13 +861,10 @@ public async Task<ReturnResult> RenameAsync(IStorageItemWithPath source, string
861861
}
862862

863863
/* Only prompt user when extension has changed,
864-
not when file name has changed
865-
*/
864+
not when file name has changed */
866865
if (Path.GetExtension(source.Path) != Path.GetExtension(newName))
867866
{
868-
var renameDialogText = "RenameFileDialog/Text".GetLocalized();
869-
870-
var yesSelected = await DialogDisplayHelper.ShowDialogAsync("Rename", renameDialogText, "Yes", "No");
867+
var yesSelected = await DialogDisplayHelper.ShowDialogAsync("RenameFileDialogTitle".GetLocalized(), "RenameFileDialog/Text".GetLocalized(), "ButtonYes/Content".GetLocalized(), "ButtonNo/Content".GetLocalized());
871868
if (yesSelected)
872869
{
873870
history = await filesystemOperations.RenameAsync(source, newName, collision, errorCode, cancellationToken);

0 commit comments

Comments
 (0)