Fix UF_HIDDEN causing st_flags to be dropped in ConvertFileStatus; add PAL_UF_HIDDEN static assert#125710
Fix UF_HIDDEN causing st_flags to be dropped in ConvertFileStatus; add PAL_UF_HIDDEN static assert#125710
Conversation
…rt for PAL_UF_HIDDEN == UF_HIDDEN Co-authored-by: danmoseley <6385855+danmoseley@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Unix PAL file-status conversion to better surface (and validate) platform stat user flags, particularly around the hidden flag (UF_HIDDEN), by changing what gets assigned into FileStatus.UserFlags.
Changes:
- Added a compile-time validation that
PAL_UF_HIDDENmatches the platform’sUF_HIDDENwhen available. - Changed
ConvertFileStatusto populateFileStatus.UserFlagsfromst_flagswhenHAVE_STAT_FLAGSis available (instead of only mappingUF_HIDDEN).
|
@danmoseley I left some feedback for @copilot. I assume I can't ask it to act on that. |
|
… UF_HIDDEN being defined Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Addressed both review points in 1a6d59a:
|
There was a problem hiding this comment.
Pull request overview
Updates the System.Native stat-to-FileStatus conversion to preserve the platform st_flags value (when available) so managed code can round-trip flags (e.g., when toggling UF_HIDDEN) without unintentionally clearing other existing file flags.
Changes:
- Add a compile-time validation that
PAL_UF_HIDDENmatches the platform’sUF_HIDDENvalue when supported. - Populate
FileStatus.UserFlagswith the fullst_flagsbitmask (instead of only mapping the hidden bit).
Adds a macOS-specific test that sets UF_NODUMP on a file, toggles Hidden via FileInfo.Attributes, and verifies UF_NODUMP survives the round-trip through ConvertFileStatus and lchflags. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Will have to rely on CI to validate this attempt at a macOS test. |
There was a problem hiding this comment.
Pull request overview
This PR updates the Unix native stat marshaling to preserve BSD st_flags values (on platforms that support UF_HIDDEN), enabling FileAttributes.Hidden toggling on macOS to retain other user flags (e.g., UF_NODUMP), and adds a regression test for that behavior.
Changes:
- Return the full
st_flagsvalue viaFileStatus.UserFlagswhen supported, instead of only projecting the hidden bit. - Add Unix interop sources (
Interop.Stat,Interop.LChflags) to the FileSystem test project to validate flag preservation. - Add a macOS-specific test ensuring toggling Hidden preserves other user flags.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/native/libs/System.Native/pal_io.c |
Populate FileStatus.UserFlags with the full st_flags (when supported) and add a static assert for UF_HIDDEN. |
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj |
Include additional Unix interop sources needed by the new test. |
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/FileInfo/GetSetAttributes.cs |
Add an OSX-only regression test for preserving other user flags when toggling Hidden. |
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/FileInfo/GetSetAttributes.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj
Show resolved
Hide resolved
The test references Interop.Sys.* types that are only available in the unix ItemGroup. Split the test into GetSetAttributes.Unix.cs (compiled only for unix TFM) and make the main class partial. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@danmoseley it's been a long time since #69004. After reviewing the PR, I think as long as the native layer maps to what we have in the managed enum we're ok, even if that is only the |
|
@tmds sorry I missed that. You're saying -- if I read flags with managed code, flip read only or whatever, and write back, it's OK if we wipe flags not represented in the managed enum? Isn't that arguably data loss (admittedly I didn't check whether we do it right and verify that elsewhere in our libraries) cc @adamsitnik |
Ah, I had missed #69004 was for the round-trip. Yes, we should address this (contrary to what I said in the previous comment). |
|
OK thanks then if test passes on macOS I think we are good to sign off. |
|
I had Copilot do a quick scan for any other places we drop flags. It only found the one this fixes. It pointed out that SetAttributes overwrites permissions but that's intentional |
Clarify that the static assert exists because LChflags and FChflags pass UserFlags values directly to the OS without remapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes a correctness issue in the Unix PAL file status conversion on Apple/BSD platforms where FileStatus.UserFlags previously collapsed st_flags down to just the hidden bit, which could cause .NET to accidentally clear other BSD file flags when toggling FileAttributes.Hidden.
Changes:
- Update
ConvertFileStatusto preserve the fullst_flagsvalue (whenUF_HIDDENis supported) instead of mapping onlyUF_HIDDEN. - Add a
c_static_assertto ensurePAL_UF_HIDDENmatches the platform’sUF_HIDDENvalue. - Add an OSX test that verifies toggling
Hiddenpreserves another user flag (UF_NODUMP).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/native/libs/System.Native/pal_io.c | Preserve all st_flags in FileStatus.UserFlags (when supported) and add a static assert for PAL_UF_HIDDEN. |
| src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj | Include required Unix interop sources and the new Unix-only FileInfo attributes test. |
| src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/FileInfo/GetSetAttributes.Unix.cs | New OSX regression test ensuring hidden toggling preserves other BSD user flags. |
| src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/FileInfo/GetSetAttributes.cs | Make the test class partial so the Unix-specific test can be added in a separate file. |
|
Copilot analysis of the failing leg -- it seems it was run on a machine where the AppleClang wasn't present, or at least wasn't found. Did anything change, or this is a misconfigured box? -=== The None of these are in our code -- they're all in Apple's own SDK headers. Root causeThe failing build agent has standalone Clang 18.1.8 ( EvidenceThe same
The agent image that has |
ConvertFileStatuswas discarding allst_flagsbits exceptUF_HIDDEN— replacing the full flag set with eitherPAL_UF_HIDDENor0. Additionally, there was no static assert ensuringPAL_UF_HIDDEN == UF_HIDDEN, which is required sinceSystemNative_LChflags/SystemNative_FChflagspass flags directly to the OS without remapping.Visible effect
On macOS, if managed code read
FileStatus.UserFlagsand then wrote them back (e.g., toggling hidden), it would silently erase any other BSD user flags on the file. For example, a file marked immutable (UF_IMMUTABLE) could lose that protection after .NET touched its hidden attribute. In practice this was low-impact since .NET rarely manipulates these flags, but it's a correctness bug.Changes
pal_io.c—ConvertFileStatus: Removed the ternary that collapsedst_flagsto a single bit. Now passes all flags through directly, gated on bothHAVE_STAT_FLAGSanddefined(UF_HIDDEN)to ensureUserFlagsremains0on platforms that lackUF_HIDDEN(preventing any unrelatedst_flagsbit from overlapping0x8000and falsely reporting files as hidden):The managed code in
FileStatus.Unix.csalready uses bitwise ops (& UF_HIDDEN,| UF_HIDDEN,& ~UF_HIDDEN) so it handles additional flags correctly.pal_io.c— static asserts block: Addedc_static_assert(PAL_UF_HIDDEN == UF_HIDDEN)under#if HAVE_STAT_FLAGS && defined(UF_HIDDEN)to catch any future divergence between the PAL constant and the OS-defined value.pal_io.c— comment fix: Corrected grammar in the static assert comment from "enum value are" to "enum values are".Fixes #69004