Skip to content

Enhance fs__chmod() and fs__access() to deal with ACLs on windows #2838

@staticfloat

Description

@staticfloat

Currently, the access() and chmod() wrappers in in src/win/fs.c do not take windows ACLs into account. These are the most common methods by which a file can have e.g. executable permissions granted/restricted. As an example, Cygwin's chmod implementation uses windows ACLs to encode the user/group/other triplet of permissions bits. The Cygwin implementation is quite complex, (you can read some of it here: https://github.com/Alexpux/Cygwin/blob/b61dc22adaf82114eee3edce91cc3433bcd27fe5/winsup/cygwin/sec_acl.cc#L130-L134) but we have been working on an implementation that is relatively self-contained, and gives us satisfying chmod() and access() semantics. We're not quite ready to open a PR to upstream this yet, as we have yet to test this in a production Julia release and be certain that it works in all edge cases (ACLs are unfortunately rather complex beasts, and we've already had to work around one win32 bug) but you can see the current state of our patch here: JuliaLang/libuv@35b1504...JuliaLang:sf/access_chmod

We are interested in any feedback from the libuv devs regarding the overall approach and any edge cases you might think of that we haven't considered. Our motivating use case for this is calculating git tree hashes, as we use that algorithm to content-address filesystem trees. This requires an accurate check on the executable permissions of the file, hence the need for fs__access() and fs__chmod() to do something useful on Windows. The rest of the machinery within fs__chmod() that sets writable and readable bits for user, group and other was me being stubborn and not wanting to half-build something that just set executable bits.

I did spend a day looking into making fs__stat_handle() work in a similar way and fill out st_mode properly. At first, I hoped that the AccessCheck() win32 call, which works so well for fs__access(), could be used with separate tokens (one for file owner, file group, and the Everyone group) and permission masks (read, write, execute) to probe the 9 bits within the rwx triplets, however there is one issue; while we can easily derive a token for the current user and the everyone group, I have not found a way to generate a token for an arbitrary user or group; I can only generate a token (via CreateRestrictedToken) for groups that the current user belongs to, by blacklisting all other group and user SIDs. This means that, for files owned by a different user or a group that that user does not belong to, the results will always be all-deny.

I haven't found any other nice win32 APIs to perform the ACL result calculation for arbitrary SIDs yet; if anyone knows of a good alternative, I'd love to have a stat() implementation that works properly. From what I can tell, Cygwin simulates the ACL permission rules internally, and that's far too much complexity for what is, for our usecases, simply a "nice to have".

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions