Skip to content

Commit 6e0c476

Browse files
authored
Create files and folder as admin (#5967)
1 parent 8866f55 commit 6e0c476

File tree

2 files changed

+147
-18
lines changed

2 files changed

+147
-18
lines changed

Files.Launcher/MessageHandlers/FileOperationsHandler.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,71 @@ await Win32API.StartSTATask(() =>
140140
await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", result } }, message.Get("RequestID", (string)null));
141141
break;
142142

143+
case "CreateFile":
144+
case "CreateFolder":
145+
{
146+
var filePath = (string)message["filepath"];
147+
var template = message.Get("template", (string)null);
148+
var dataStr = message.Get("data", (string)null);
149+
var (success, shellOperationResult) = await Win32API.StartSTATask(async () =>
150+
{
151+
using (var op = new ShellFileOperations())
152+
{
153+
op.Options = ShellFileOperations.OperationFlags.Silent
154+
| ShellFileOperations.OperationFlags.NoConfirmMkDir
155+
| ShellFileOperations.OperationFlags.RenameOnCollision
156+
| ShellFileOperations.OperationFlags.NoErrorUI;
157+
158+
var shellOperationResult = new ShellOperationResult();
159+
160+
using var shd = new ShellFolder(Path.GetDirectoryName(filePath));
161+
op.QueueNewItemOperation(shd, Path.GetFileName(filePath),
162+
(string)message["fileop"] == "CreateFolder" ? FileAttributes.Directory : FileAttributes.Normal, template);
163+
164+
var createTcs = new TaskCompletionSource<bool>();
165+
op.PostNewItem += (s, e) =>
166+
{
167+
shellOperationResult.Items.Add(new ShellOperationItemResult()
168+
{
169+
Succeeded = e.Result.Succeeded,
170+
Destination = e.DestItem?.FileSystemPath,
171+
HRresult = (int)e.Result
172+
});
173+
};
174+
op.FinishOperations += (s, e) => createTcs.TrySetResult(e.Result.Succeeded);
175+
176+
try
177+
{
178+
op.PerformOperations();
179+
}
180+
catch
181+
{
182+
createTcs.TrySetResult(false);
183+
}
184+
185+
if (dataStr != null && (shellOperationResult.Items.SingleOrDefault()?.Succeeded ?? false))
186+
{
187+
Extensions.IgnoreExceptions(() =>
188+
{
189+
var dataBytes = Convert.FromBase64String(dataStr);
190+
using (var fs = new FileStream(shellOperationResult.Items.Single().Destination, FileMode.Open))
191+
{
192+
fs.Write(dataBytes, 0, dataBytes.Length);
193+
fs.Flush();
194+
}
195+
}, Program.Logger);
196+
}
197+
198+
return (await createTcs.Task, shellOperationResult);
199+
}
200+
});
201+
await Win32API.SendMessageAsync(connection, new ValueSet() {
202+
{ "Success", success },
203+
{ "Result", JsonConvert.SerializeObject(shellOperationResult) }
204+
}, message.Get("RequestID", (string)null));
205+
}
206+
break;
207+
143208
case "DeleteItem":
144209
{
145210
var fileToDeletePath = ((string)message["filepath"]).Split('|');

Files/Filesystem/FilesystemOperations/FilesystemOperations.cs

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public FilesystemOperations(IShellPage associatedInstance)
5454

5555
public async Task<(IStorageHistory, IStorageItem)> CreateAsync(IStorageItemWithPath source, IProgress<FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
5656
{
57-
IStorageItem item = null;
57+
IStorageItemWithPath item = null;
5858
try
5959
{
6060
switch (source.ItemType)
@@ -64,22 +64,82 @@ public FilesystemOperations(IShellPage associatedInstance)
6464
var newEntryInfo = await RegistryHelper.GetNewContextMenuEntryForType(Path.GetExtension(source.Path));
6565
if (newEntryInfo == null)
6666
{
67-
BaseStorageFolder folder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(PathNormalization.GetParentDir(source.Path));
68-
item = await folder.CreateFileAsync(Path.GetFileName(source.Path));
67+
var fsFolderResult = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(PathNormalization.GetParentDir(source.Path));
68+
var fsResult = (FilesystemResult)false;
69+
if (fsFolderResult)
70+
{
71+
var fsCreateResult = await FilesystemTasks.Wrap(() => fsFolderResult.Result.CreateFileAsync(Path.GetFileName(source.Path), CreationCollisionOption.GenerateUniqueName).AsTask());
72+
fsResult = fsCreateResult;
73+
item = fsCreateResult.Result.FromStorageItem();
74+
}
75+
if (fsResult == FileSystemStatusCode.Unauthorized)
76+
{
77+
(var fsAdminResult, var shellOpRes) = await PerformAdminOperation(new ValueSet()
78+
{
79+
{ "Arguments", "FileOperation" },
80+
{ "fileop", "CreateFile" },
81+
{ "filepath", source.Path }
82+
});
83+
if (fsAdminResult)
84+
{
85+
fsResult = fsAdminResult;
86+
item = StorageItemHelpers.FromPathAndType(shellOpRes.Items.SingleOrDefault()?.Destination, FilesystemItemType.File);
87+
}
88+
}
6989
}
7090
else
7191
{
72-
item = (await newEntryInfo.Create(source.Path, associatedInstance)).Result;
92+
var fsCreateResult = await newEntryInfo.Create(source.Path, associatedInstance);
93+
if (fsCreateResult)
94+
{
95+
item = fsCreateResult.Result.FromStorageItem();
96+
}
97+
var fsResult = (FilesystemResult)fsCreateResult.ErrorCode;
98+
if (fsResult == FileSystemStatusCode.Unauthorized)
99+
{
100+
(var fsAdminResult, var shellOpRes) = await PerformAdminOperation(new ValueSet()
101+
{
102+
{ "Arguments", "FileOperation" },
103+
{ "fileop", "CreateFile" },
104+
{ "filepath", source.Path },
105+
{ "template", newEntryInfo.Template },
106+
{ "data", newEntryInfo.Data }
107+
});
108+
if (fsAdminResult && shellOpRes.Items.Count == 1)
109+
{
110+
fsResult = fsAdminResult;
111+
item = StorageItemHelpers.FromPathAndType(shellOpRes.Items.Single().Destination, FilesystemItemType.File);
112+
}
113+
}
73114
}
74115

75116
break;
76117
}
77118

78119
case FilesystemItemType.Directory:
79120
{
80-
BaseStorageFolder folder = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(PathNormalization.GetParentDir(source.Path));
81-
item = await folder.CreateFolderAsync(Path.GetFileName(source.Path));
82-
121+
var fsFolderResult = await associatedInstance.FilesystemViewModel.GetFolderFromPathAsync(PathNormalization.GetParentDir(source.Path));
122+
var fsResult = (FilesystemResult)false;
123+
if (fsFolderResult)
124+
{
125+
var fsCreateResult = await FilesystemTasks.Wrap(() => fsFolderResult.Result.CreateFolderAsync(Path.GetFileName(source.Path), CreationCollisionOption.GenerateUniqueName).AsTask());
126+
fsResult = fsCreateResult;
127+
item = fsCreateResult.Result.FromStorageItem();
128+
}
129+
if (fsResult == FileSystemStatusCode.Unauthorized)
130+
{
131+
(var fsAdminResult, var shellOpRes) = await PerformAdminOperation(new ValueSet()
132+
{
133+
{ "Arguments", "FileOperation" },
134+
{ "fileop", "CreateFolder" },
135+
{ "filepath", source.Path }
136+
});
137+
if (fsAdminResult && shellOpRes.Items.Count == 1)
138+
{
139+
fsResult = fsAdminResult;
140+
item = StorageItemHelpers.FromPathAndType(shellOpRes.Items.Single().Destination, FilesystemItemType.Directory);
141+
}
142+
}
83143
break;
84144
}
85145

@@ -89,7 +149,11 @@ public FilesystemOperations(IShellPage associatedInstance)
89149
}
90150

91151
errorCode?.Report(FileSystemStatusCode.Success);
92-
return (new StorageHistory(FileOperationType.CreateNew, source.CreateEnumerable(), null), item);
152+
if (item != null)
153+
{
154+
return (new StorageHistory(FileOperationType.CreateNew, item.CreateEnumerable(), null), item.Item);
155+
}
156+
return (null, null);
93157
}
94158
catch (Exception e)
95159
{
@@ -195,7 +259,7 @@ await DialogDisplayHelper.ShowDialogAsync(
195259
}
196260
if (fsResult == FileSystemStatusCode.Unauthorized)
197261
{
198-
fsResult = await PerformAdminOperation(new ValueSet()
262+
(fsResult, _) = await PerformAdminOperation(new ValueSet()
199263
{
200264
{ "Arguments", "FileOperation" },
201265
{ "fileop", "CopyItem" },
@@ -253,7 +317,7 @@ await DialogDisplayHelper.ShowDialogAsync(
253317
}
254318
if (fsResult == FileSystemStatusCode.Unauthorized)
255319
{
256-
fsResult = await PerformAdminOperation(new ValueSet()
320+
(fsResult, _) = await PerformAdminOperation(new ValueSet()
257321
{
258322
{ "Arguments", "FileOperation" },
259323
{ "fileop", "CopyItem" },
@@ -418,7 +482,7 @@ await DialogDisplayHelper.ShowDialogAsync(
418482
}
419483
if (fsResult == FileSystemStatusCode.Unauthorized || fsResult == FileSystemStatusCode.ReadOnly)
420484
{
421-
fsResult = await PerformAdminOperation(new ValueSet()
485+
(fsResult, _) = await PerformAdminOperation(new ValueSet()
422486
{
423487
{ "Arguments", "FileOperation" },
424488
{ "fileop", "MoveItem" },
@@ -464,7 +528,7 @@ await DialogDisplayHelper.ShowDialogAsync(
464528
}
465529
if (fsResult == FileSystemStatusCode.Unauthorized || fsResult == FileSystemStatusCode.ReadOnly)
466530
{
467-
fsResult = await PerformAdminOperation(new ValueSet()
531+
(fsResult, _) = await PerformAdminOperation(new ValueSet()
468532
{
469533
{ "Arguments", "FileOperation" },
470534
{ "fileop", "MoveItem" },
@@ -558,7 +622,7 @@ public async Task<IStorageHistory> DeleteAsync(IStorageItemWithPath source,
558622
// not neeeded if called after trying with ShellFilesystemOperations
559623
if (!fsResult)
560624
{
561-
fsResult = await PerformAdminOperation(new ValueSet()
625+
(fsResult, _) = await PerformAdminOperation(new ValueSet()
562626
{
563627
{ "Arguments", "FileOperation" },
564628
{ "fileop", "DeleteItem" },
@@ -674,7 +738,7 @@ public async Task<IStorageHistory> RenameAsync(IStorageItemWithPath source,
674738
}
675739
else
676740
{
677-
var fsResult = await PerformAdminOperation(new ValueSet()
741+
var (fsResult, _) = await PerformAdminOperation(new ValueSet()
678742
{
679743
{ "Arguments", "FileOperation" },
680744
{ "fileop", "RenameItem" },
@@ -785,7 +849,7 @@ public async Task<IStorageHistory> RestoreFromTrashAsync(IStorageItemWithPath so
785849
}
786850
if (fsResult == FileSystemStatusCode.Unauthorized || fsResult == FileSystemStatusCode.ReadOnly)
787851
{
788-
fsResult = await PerformAdminOperation(new ValueSet()
852+
(fsResult, _) = await PerformAdminOperation(new ValueSet()
789853
{
790854
{ "Arguments", "FileOperation" },
791855
{ "fileop", "MoveItem" },
@@ -870,7 +934,7 @@ private static async Task<BaseStorageFolder> MoveDirectoryAsync(BaseStorageFolde
870934
return createdRoot;
871935
}
872936

873-
private async Task<FilesystemResult> PerformAdminOperation(ValueSet operation)
937+
private async Task<(FilesystemResult, ShellOperationResult)> PerformAdminOperation(ValueSet operation)
874938
{
875939
var elevateConfirmDialog = new Files.Dialogs.ElevateConfirmDialog();
876940
var elevateConfirmResult = await elevateConfirmDialog.ShowAsync();
@@ -888,11 +952,11 @@ private async Task<FilesystemResult> PerformAdminOperation(ValueSet operation)
888952
&& response.Get("Success", false));
889953
var shellOpResult = JsonConvert.DeserializeObject<ShellOperationResult>(response.Get("Result", "{\"Items\": []}"));
890954
fsResult &= (FilesystemResult)shellOpResult.Items.All(x => x.Succeeded);
891-
return fsResult;
955+
return (fsResult, shellOpResult);
892956
}
893957
}
894958
}
895-
return (FilesystemResult)false;
959+
return ((FilesystemResult)false, null);
896960
}
897961

898962
#endregion Helpers

0 commit comments

Comments
 (0)