Skip to content

Feature: Added support for elevated file operations #13043

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 25, 2023
Merged
2 changes: 1 addition & 1 deletion src/Files.App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private IHost ConfigureHost()
.AddSingleton<IDisplayPageContext, DisplayPageContext>()
.AddSingleton<IWindowContext, WindowContext>()
.AddSingleton<IMultitaskingContext, MultitaskingContext>()
.AddSingleton<ITagsContext, TagsContext>()
.AddSingleton<ITagsContext, TagsContext>()
.AddSingleton<IDialogService, DialogService>()
.AddSingleton<IImageService, ImagingService>()
.AddSingleton<IThreadingService, ThreadingService>()
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Helpers/Win32Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static async Task<bool> InvokeWin32ComponentsAsync(IEnumerable<string> ap

if (runAsAdmin)
{
return await LaunchHelper.LaunchAppAsync(application, "runas", workingDirectory);
return await LaunchHelper.LaunchAppAsync(application, "RunAs", workingDirectory);
}
else
{
Expand Down
37 changes: 32 additions & 5 deletions src/Files.App/Utils/Storage/Helpers/FileOperationsHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
});
}

public static Task<(bool, ShellOperationResult)> CreateItemAsync(string filePath, string fileOp, string template = "", byte[]? dataBytes = null)
public static Task<(bool, ShellOperationResult)> CreateItemAsync(string filePath, string fileOp, long ownerHwnd, bool asAdmin, string template = "", byte[]? dataBytes = null)
{
return Win32API.StartSTATask(async () =>
{
Expand All @@ -47,6 +47,12 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
| ShellFileOperations.OperationFlags.NoConfirmMkDir
| ShellFileOperations.OperationFlags.RenameOnCollision
| ShellFileOperations.OperationFlags.NoErrorUI;
if (asAdmin)
{
op.Options |= ShellFileOperations.OperationFlags.ShowElevationPrompt
| ShellFileOperations.OperationFlags.RequireElevation;
}
op.OwnerWindow = (IntPtr)ownerHwnd;

var shellOperationResult = new ShellOperationResult();

Expand Down Expand Up @@ -188,7 +194,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
});
}

public static Task<(bool, ShellOperationResult)> DeleteItemAsync(string[] fileToDeletePath, bool permanently, long ownerHwnd, IProgress<FileSystemProgress> progress, string operationID = "")
public static Task<(bool, ShellOperationResult)> DeleteItemAsync(string[] fileToDeletePath, bool permanently, long ownerHwnd, bool asAdmin, IProgress<FileSystemProgress> progress, string operationID = "")
{
operationID = string.IsNullOrEmpty(operationID) ? Guid.NewGuid().ToString() : operationID;

Expand All @@ -202,6 +208,11 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
op.Options = ShellFileOperations.OperationFlags.Silent
| ShellFileOperations.OperationFlags.NoConfirmation
| ShellFileOperations.OperationFlags.NoErrorUI;
if (asAdmin)
{
op.Options |= ShellFileOperations.OperationFlags.ShowElevationPrompt
| ShellFileOperations.OperationFlags.RequireElevation;
}
op.OwnerWindow = (IntPtr)ownerHwnd;
if (!permanently)
{
Expand Down Expand Up @@ -276,7 +287,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
});
}

public static Task<(bool, ShellOperationResult)> RenameItemAsync(string fileToRenamePath, string newName, bool overwriteOnRename, string operationID = "")
public static Task<(bool, ShellOperationResult)> RenameItemAsync(string fileToRenamePath, string newName, bool overwriteOnRename, long ownerHwnd, bool asAdmin, string operationID = "")
{
operationID = string.IsNullOrEmpty(operationID) ? Guid.NewGuid().ToString() : operationID;

Expand All @@ -289,6 +300,12 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera

op.Options = ShellFileOperations.OperationFlags.Silent
| ShellFileOperations.OperationFlags.NoErrorUI;
if (asAdmin)
{
op.Options |= ShellFileOperations.OperationFlags.ShowElevationPrompt
| ShellFileOperations.OperationFlags.RequireElevation;
}
op.OwnerWindow = (IntPtr)ownerHwnd;
op.Options |= !overwriteOnRename ? ShellFileOperations.OperationFlags.RenameOnCollision : 0;

if (!SafetyExtensions.IgnoreExceptions(() =>
Expand Down Expand Up @@ -337,7 +354,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
});
}

public static Task<(bool, ShellOperationResult)> MoveItemAsync(string[] fileToMovePath, string[] moveDestination, bool overwriteOnMove, long ownerHwnd, IProgress<FileSystemProgress> progress, string operationID = "")
public static Task<(bool, ShellOperationResult)> MoveItemAsync(string[] fileToMovePath, string[] moveDestination, bool overwriteOnMove, long ownerHwnd, bool asAdmin, IProgress<FileSystemProgress> progress, string operationID = "")
{
operationID = string.IsNullOrEmpty(operationID) ? Guid.NewGuid().ToString() : operationID;

Expand All @@ -353,6 +370,11 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
op.Options = ShellFileOperations.OperationFlags.NoConfirmMkDir
| ShellFileOperations.OperationFlags.Silent
| ShellFileOperations.OperationFlags.NoErrorUI;
if (asAdmin)
{
op.Options |= ShellFileOperations.OperationFlags.ShowElevationPrompt
| ShellFileOperations.OperationFlags.RequireElevation;
}
op.OwnerWindow = (IntPtr)ownerHwnd;
op.Options |= !overwriteOnMove ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision
: ShellFileOperations.OperationFlags.NoConfirmation;
Expand Down Expand Up @@ -417,7 +439,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
});
}

public static Task<(bool, ShellOperationResult)> CopyItemAsync(string[] fileToCopyPath, string[] copyDestination, bool overwriteOnCopy, long ownerHwnd, IProgress<FileSystemProgress> progress, string operationID = "")
public static Task<(bool, ShellOperationResult)> CopyItemAsync(string[] fileToCopyPath, string[] copyDestination, bool overwriteOnCopy, long ownerHwnd, bool asAdmin, IProgress<FileSystemProgress> progress, string operationID = "")
{
operationID = string.IsNullOrEmpty(operationID) ? Guid.NewGuid().ToString() : operationID;

Expand All @@ -434,6 +456,11 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera
op.Options = ShellFileOperations.OperationFlags.NoConfirmMkDir
| ShellFileOperations.OperationFlags.Silent
| ShellFileOperations.OperationFlags.NoErrorUI;
if (asAdmin)
{
op.Options |= ShellFileOperations.OperationFlags.ShowElevationPrompt
| ShellFileOperations.OperationFlags.RequireElevation;
}
op.OwnerWindow = (IntPtr)ownerHwnd;
op.Options |= !overwriteOnCopy ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision
: ShellFileOperations.OperationFlags.NoConfirmation;
Expand Down
21 changes: 15 additions & 6 deletions src/Files.App/Utils/Storage/Operations/FilesystemOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public FilesystemOperations(IShellPage associatedInstance)
this._associatedInstance = associatedInstance;
}

public async Task<(IStorageHistory, IStorageItem)> CreateAsync(IStorageItemWithPath source, IProgress<FileSystemProgress> progress, CancellationToken cancellationToken)
public async Task<(IStorageHistory, IStorageItem)> CreateAsync(IStorageItemWithPath source, IProgress<FileSystemProgress> progress, CancellationToken cancellationToken, bool asAdmin = false)
{
IStorageItemWithPath item = null;
FilesystemResult fsResult = (FilesystemResult)false;
Expand Down Expand Up @@ -546,7 +546,12 @@ public Task<IStorageHistory> RenameAsync(IStorageItem source, string newName, Na
return RenameAsync(StorageHelpers.FromStorageItem(source), newName, collision, progress, cancellationToken);
}

public async Task<IStorageHistory> RenameAsync(IStorageItemWithPath source, string newName, NameCollisionOption collision, IProgress<FileSystemProgress> progress, CancellationToken cancellationToken)
public async Task<IStorageHistory> RenameAsync(IStorageItemWithPath source,
string newName,
NameCollisionOption collision,
IProgress<FileSystemProgress> progress,
CancellationToken cancellationToken,
bool asAdmin = false)
{
FileSystemProgress fsProgress = new(progress, true, FileSystemStatusCode.InProgress);

Expand Down Expand Up @@ -646,7 +651,11 @@ public async Task<IStorageHistory> RestoreItemsFromTrashAsync(IList<IStorageItem
return await RestoreItemsFromTrashAsync(await source.Select((item) => item.FromStorageItem()).ToListAsync(), destination, progress, cancellationToken);
}

public async Task<IStorageHistory> RestoreItemsFromTrashAsync(IList<IStorageItemWithPath> source, IList<string> destination, IProgress<FileSystemProgress> progress, CancellationToken token)
public async Task<IStorageHistory> RestoreItemsFromTrashAsync(IList<IStorageItemWithPath> source,
IList<string> destination,
IProgress<FileSystemProgress> progress,
CancellationToken token,
bool asAdmin = false)
{
FileSystemProgress fsProgress = new(progress, true, FileSystemStatusCode.InProgress, source.Count);
fsProgress.Report();
Expand Down Expand Up @@ -787,7 +796,7 @@ public async Task<IStorageHistory> CopyItemsAsync(IList<IStorageItem> source, IL
return await CopyItemsAsync(await source.Select((item) => item.FromStorageItem()).ToListAsync(), destination, collisions, progress, cancellationToken);
}

public async Task<IStorageHistory> CopyItemsAsync(IList<IStorageItemWithPath> source, IList<string> destination, IList<FileNameConflictResolveOptionType> collisions, IProgress<FileSystemProgress> progress, CancellationToken token)
public async Task<IStorageHistory> CopyItemsAsync(IList<IStorageItemWithPath> source, IList<string> destination, IList<FileNameConflictResolveOptionType> collisions, IProgress<FileSystemProgress> progress, CancellationToken token, bool asAdmin = false)
{
FileSystemProgress fsProgress = new(progress, true, FileSystemStatusCode.InProgress, source.Count);
fsProgress.Report();
Expand Down Expand Up @@ -831,7 +840,7 @@ public async Task<IStorageHistory> MoveItemsAsync(IList<IStorageItem> source, IL
return await MoveItemsAsync(await source.Select((item) => item.FromStorageItem()).ToListAsync(), destination, collisions, progress, cancellationToken);
}

public async Task<IStorageHistory> MoveItemsAsync(IList<IStorageItemWithPath> source, IList<string> destination, IList<FileNameConflictResolveOptionType> collisions, IProgress<FileSystemProgress> progress, CancellationToken token)
public async Task<IStorageHistory> MoveItemsAsync(IList<IStorageItemWithPath> source, IList<string> destination, IList<FileNameConflictResolveOptionType> collisions, IProgress<FileSystemProgress> progress, CancellationToken token, bool asAdmin = false)
{
FileSystemProgress fsProgress = new(progress, true, FileSystemStatusCode.InProgress, source.Count);
fsProgress.Report();
Expand Down Expand Up @@ -874,7 +883,7 @@ public async Task<IStorageHistory> DeleteItemsAsync(IList<IStorageItem> source,
return await DeleteItemsAsync(await source.Select((item) => item.FromStorageItem()).ToListAsync(), progress, permanently, cancellationToken);
}

public async Task<IStorageHistory> DeleteItemsAsync(IList<IStorageItemWithPath> source, IProgress<FileSystemProgress> progress, bool permanently, CancellationToken token)
public async Task<IStorageHistory> DeleteItemsAsync(IList<IStorageItemWithPath> source, IProgress<FileSystemProgress> progress, bool permanently, CancellationToken token, bool asAdmin = false)
{
FileSystemProgress fsProgress = new(progress, true, FileSystemStatusCode.InProgress, source.Count);
fsProgress.Report();
Expand Down
18 changes: 12 additions & 6 deletions src/Files.App/Utils/Storage/Operations/IFilesystemOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public interface IFilesystemOperations : IDisposable
Task<(IStorageHistory, IStorageItem)> CreateAsync(
IStorageItemWithPath source,
IProgress<FileSystemProgress> process,
CancellationToken cancellationToken);
CancellationToken cancellationToken,
bool asAdmin = false);

Task<IStorageHistory> CreateShortcutItemsAsync(
IList<IStorageItemWithPath> source,
Expand Down Expand Up @@ -96,7 +97,8 @@ Task<IStorageHistory> CopyItemsAsync(
IList<string> destination,
IList<FileNameConflictResolveOptionType> collisions,
IProgress<FileSystemProgress> progress,
CancellationToken cancellationToken);
CancellationToken cancellationToken,
bool asAdmin = false);

/// <summary>
/// Moves <paramref name="source"/> to <paramref name="destination"/> fullPath
Expand Down Expand Up @@ -158,7 +160,8 @@ Task<IStorageHistory> MoveItemsAsync(
IList<string> destination,
IList<FileNameConflictResolveOptionType> collisions,
IProgress<FileSystemProgress> progress,
CancellationToken cancellationToken);
CancellationToken cancellationToken,
bool asAdmin = false);

/// <summary>
/// Deletes <paramref name="source"/>
Expand Down Expand Up @@ -222,7 +225,8 @@ Task<IStorageHistory> DeleteItemsAsync(
IList<IStorageItemWithPath> source,
IProgress<FileSystemProgress> progress,
bool permanently,
CancellationToken cancellationToken);
CancellationToken cancellationToken,
bool asAdmin = false);

/// <summary>
/// Renames <paramref name="source"/> with <paramref name="newName"/>
Expand Down Expand Up @@ -262,7 +266,8 @@ Task<IStorageHistory> RenameAsync(
string newName,
NameCollisionOption collision,
IProgress<FileSystemProgress> progress,
CancellationToken cancellationToken);
CancellationToken cancellationToken,
bool asAdmin = false);

/// <summary>
/// Restores <paramref name="source"/> from the RecycleBin to <paramref name="destination"/> fullPath
Expand Down Expand Up @@ -319,7 +324,8 @@ Task<IStorageHistory> RestoreItemsFromTrashAsync(
IList<IStorageItemWithPath> source,
IList<string> destination,
IProgress<FileSystemProgress> progress,
CancellationToken cancellationToken);
CancellationToken cancellationToken,
bool asAdmin = false);

/// <summary>
/// Restores <paramref name="source"/> from the RecycleBin to <paramref name="destination"/> fullPath
Expand Down
Loading