Question: Why the file dragged into a UWP app is read-only?
See original GitHub issueHey folks,
I have a question bothers me for quite a while: “If user drag a storage file into a UWP app, it will be read-only by default. If you try to save changes on top of this file, you will get UnauthorizedAccessException, but why?”
For example, this is how you get the file(s) from DragEventArgs:
var storageItems = await args.DataView.GetStorageItemsAsync();
And this will be true for the files you dragged in:
public static bool IsFileReadOnly(StorageFile file)
{
return (file.Attributes & Windows.Storage.FileAttributes.ReadOnly) != 0;
}
And you will see exception if you do this:
using (var stream = await file.OpenStreamForWriteAsync()) { }
This does not make any sense to me, because if user drag a file into an app, he or she is fully aware of the operation and should just give the app same permission just like what the file open picker does. Another approach would be asking for broadSystemAccess, but it makes little sense to me as well for just enabling write to a dragged file? (+ @soumyamahunt for visibility)
Last year, when I started my notepads app. I did some research online and found out that not only me, but also thousands of developers voted for this change on MS Voice (I am not sure if it is this forum) but never received official response from MSFT. Not only that, the website is now deprecated so I cannot find and paste the link here.
Now here comes the interesting part: I recently knows that from @yaichenbaum that if you use PathIO API to write, you can workaround this limitation. Then we have a community member (@Maickonn) sent out a PR for this workaround, let me paste the interesting workaround logic here:
if (IsFileReadOnly(file) || !await FileIsWritable(file))
{
// For file(s) dragged into Notepads, they are read-only
// StorageFile API won't work but can be overwritten by Win32 PathIO API (exploit?)
// In case the file is actually read-only, WriteBytesAsync will throw UnauthorizedAccessException exception
var content = encoding.GetBytes(text);
var result = encoding.GetPreamble().Concat(content).ToArray();
await PathIO.WriteBytesAsync(file.Path, result);
}
else // Use StorageFile API to save
{
using (var stream = await file.OpenStreamForWriteAsync())
using (var writer = new StreamWriter(stream, encoding))
{
stream.Position = 0;
await writer.WriteAsync(text);
await writer.FlushAsync();
// Truncate
stream.SetLength(stream.Position);
}
}
So basically PathIO.WriteBytesAsync can write to the file although it is marked as read-only for the StorageFile item. This looks like an exploit to me and I am very confused.
So, here are my questions:
- Why the file dragged into a UWP app is read-only, what is the reason behind it? Why we never change this behavior for so many years? This literally stops any notepad like or VSCode like document editing UWP app from working properly with dragged file. And further making them weaker comparing to their win32 counterparts.
- Why PathIO.WriteBytesAsync can write to a read-only StorageFile? I know I am using the “file.Path” here instead of the runtime object, but it should be caught by the file security model, isn’t it? Or is this intended?
- Is there any plan for changing this behavior in the future or is there any plan to address it as part of WinUI 3.0 or post WinUI 3.0?
Note: If the file is already “read-only” before dragging or becoming “read-only” after dragging, none of these API will work anyway. So we are safe here. There is no bugs or concerns regarding to that topic.
Thanks, Jackie
Issue Analytics
- State:
- Created 3 years ago
- Reactions:15
- Comments:14 (7 by maintainers)
Top GitHub Comments
I think this has to do with DataPackage and DataPackageView classes especially how DataPackage.SetStorageItems method is implemented. The default behavior of SetStorageItems is to make the provided storage items readonly unless the app explicitly provides readonly attribute as false when drag of an item is starting from a given app. MS has to change this default behavior or make changes to set the readonly attribute as false in file explorer code behind.
Exactly, and it makes no sense to let user give BroadFileSystemAccess to a simple notepad app at all.