-
Notifications
You must be signed in to change notification settings - Fork 824
fix: Map FileAccessMode to appropriate FileMode in StorageFile.OpenStreamAsync #21663
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
base: master
Are you sure you want to change the base?
Conversation
…OpenStreamAsync Co-authored-by: MartinZikmund <[email protected]>
|
|
1 similar comment
|
|
Co-authored-by: MartinZikmund <[email protected]>
|
🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-21663/docs/index.html |
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes a bug where StorageFile.OpenStreamAsync was always using FileMode.Open regardless of the FileAccessMode parameter, causing FileNotFoundException when attempting to write to non-existent files on Skia.Desktop and iOS platforms.
Key Changes:
- Added
ToFileModehelper method to properly mapFileAccessModetoFileMode - Updated
OpenStreamAsyncimplementations in both Local and iOS variants to use the new mapping - Added runtime test to verify the fix
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/Uno.UWP/Storage/StorageFile.cs |
Added ToFileMode helper method to map FileAccessMode to appropriate FileMode |
src/Uno.UWP/Storage/StorageFile.Local.cs |
Updated OpenStreamAsync to use ToFileMode instead of hardcoded FileMode.Open |
src/Uno.UWP/Storage/StorageFile.iOS.cs |
Updated iOS implementation of OpenStreamAsync to use ToFileMode |
src/Uno.UI.RuntimeTests/Tests/Windows_Storage/Given_StorageFile_Native.base.cs |
Added test to verify writing to non-existent files works correctly |
| private static FileMode ToFileMode(FileAccessMode accessMode) | ||
| => accessMode switch | ||
| { | ||
| FileAccessMode.Read => FileMode.Open, | ||
| FileAccessMode.ReadWrite => FileMode.OpenOrCreate, | ||
| _ => throw new ArgumentOutOfRangeException(nameof(accessMode)) | ||
| }; |
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ToFileMode method should include XML documentation explaining the mapping rationale. Specifically, it should document why FileAccessMode.ReadWrite maps to FileMode.OpenOrCreate (to create files that don't exist) and why FileAccessMode.Read maps to FileMode.Open (to ensure the file exists before reading).
Issue
StorageFile.OpenStreamAsyncwas always usingFileMode.Openregardless of theFileAccessModeargument, causingFileNotFoundExceptionwhen attempting to write to files that don't exist yet.This issue affected Skia.Desktop (macOS, Linux, Windows) and iOS platforms when using APIs like:
FileIO.WriteTextAsync()on new filesOpenStreamForWriteAsync()on files that haven't been created yetRoot Cause
The Local and iOS implementations of
OpenStreamAsyncwere hardcoded to useFileMode.Open:FileMode.Openrequires the file to exist, so whenFileAccessMode.ReadWritewas passed (as happens withOpenStreamForWriteAsync), it would throwFileNotFoundExceptioninstead of creating the file.Solution
Added a
ToFileModehelper method that mapsFileAccessModeto the appropriateFileMode:FileAccessMode.Read→FileMode.Open(requires file to exist)FileAccessMode.ReadWrite→FileMode.OpenOrCreate(creates file if it doesn't exist)Updated both
StorageFile.Local.csandStorageFile.iOS.csimplementations to use this mapping:Changes
ToFileModehelper method inStorageFile.csStorageFile.Local.OpenStreamAsyncto respectFileAccessModeStorageFile.iOS.SecurityScopedFile.OpenStreamAsyncto respectFileAccessModeWhen_OpenStreamForWriteAsync_On_New_Fileto verify the fixTesting
✅ Writing to non-existent files now works correctly (creates the file)
✅ Reading from non-existent files still throws
FileNotFoundExceptionas expected✅ Existing tests continue to pass
✅ Manual verification confirms the fix resolves the reported issue
Closes #XXXXX
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
crl.godaddy.comdotnet restore Uno.UWP/Uno.Tests.csproj(dns block)ocsp.godaddy.comdotnet restore Uno.UWP/Uno.Tests.csproj(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
This section details on the original issue you should resolve
<issue_title>
StorageFile.Local.OpenStreamAsyncalways useFile.Openinstead of theFileAccessModeargument</issue_title><issue_description>### Current behavior 🐛
FileNotFoundExceptionthrown when trying to write new StorageFile in a Skia.Desktop Mac app.Expected behavior 🎯
No exception thrown with correct entitlements or choice of output folder
How to reproduce it (as minimally and precisely as possible) 🔬
Demo project: https://github.com/baskren/MacDesktop_StorageFile_Write
Relevant configurations:
entitlements.plist [CLICK HERE TO EXPAND]
.csproj, in the<Properties>group:Workaround 🛠️
None known at this time
Renderer 🎨
Affected platforms 📱💻🖥️
Desktop (macOS)
Uno.Sdk version (and other relevant versions) 📦
Uno.Sdk: 6.1.23
UnoFeatures:
IDE version 🧑💻
Click to expand [Mac Dev Environment]
JetBrains Rider
JetBrains Rider 2025.2
Build #RD-252.23892.524, built on August 12, 2025
Source revision: 18364647ddbb4
Licensed to Ben Askren
Subscription is active until July 10, 2026.
Runtime version: 21.0.7+6-b1038.58 aarch64 (JCEF 122.1.9)
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Toolkit: sun.lwawt.macosx.LWCToolkit
macOS 15.6
.NET Core v8.0.11 ARM64 (Server GC)
GC: G1 Young Generation, G1 Concurrent GC, G1 Old Generation
Memory: 4096M
Cores: 12
Metal Rendering is ON
Registry:
ide.lookup.shrink=true
ide.experimental.ui=true
llm.show.ai.promotion.window.on.start=false
Non-Bundled Plugins:
org.antlr.intellij.plugin (1.24)
com.intellij.resharper.HeapAllocationsViewer (2025.1.0)
com.intellij.copyright (252.23892.464)
com.redhat.devtools.lsp4ij (0.14.2)
lermitage.intellij.iconviewer (1.31.3)
com.github.camork.fileExpander (2.5)
com.wakatime.intellij.plugin (15.0.4)
com.cppcxy.Intellij-SumnekoLua (3.15.0.46-IDEA243)
com.jetbrains.rider.android (252.23892.524)
unoplatform (1.5.19)
Karma (252.25204.0)
me.rafaelldi.aspire (1.8.8)
com.intellij.resharper.azure (4.5.3)
Anything else we need to know? 💬
No response</issue_description>
Comments on the Issue (you are @copilot in this section)
@spouliot https://github.com/baskren/MacDesktop_StorageFile_Write is a 404. Is it public ? @spouliot Your `entitlements.plist` above does not match the one inside the repo.However that's not the problem. Entitlements are only needed if/when the app is packaged as an app bundle (and in the case of this entitlement the app would have to be sandboxed to need this).
For a dotnet app the file system is accessible with the same permission that the current user (launching the app) has.
The full exception is: