Extend std::fs::Permissions on Windows

Hi,

I need to set file attributes on Windows, and I found it's exactly what std::fs::set_permissions does. However, struct std::fs::Permissions only exposes attribute readonly. I would also need to set other attributes, such as FILE_ATTRIBUTE_SYSTEM or FILE_ATTRIBUTE_TEMPORARY.

On Linux, there is extension trait std::os::unix::fs::PermissionsExt, but it seems Windows has no such thing, making struct Permissions not as useful as it may be.

Adding a Default implementation to create a FILE_ATTRIBUTE_NORMAL could be great as well.

Currently, I'm calling system API SetFileAttributesW directly, but this forces me to resort to unsafe code and to re-implement conversion from Path to Vec<u16> (in a way that's probably less efficient than the standard library).

Another possibility would be to compute the mask manually and to transmute the result to Permissions (which is basically a u32), but I don't like this solution because there is no guarantee that Permissions will remain equivalent to a u32 in the future.

There is a attributes method on the Windows extension trait for OpenOptions: https://doc.rust-lang.org/nightly/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.attributes If you want to create/open the file and at the same time set attributes you can probably use this method.

The standard library uses path.encode_wide() from std::os::windows::ffi::OsStrExt I believe.

There is a attributes method on the Windows extension trait for OpenOptions

This is indeed the solution I'm using for new files. However, according to the doc, the attributes given to OpenOptions are only applied to existing files if the files are open with .create(true).truncate(true), which truncates the files. Anyway, using std::fs::OpenOptions::new().create(true).truncate(true).attributes(attrs).open(path) gives me an "InvalidInput" error.

I need to set the attributes to an existing file, without changing its contents.

The Microsoft docs suggest that the attributes being ignored when opening an existing file is a property of the Win32 API, not the Rust API:

When CreateFile2 opens an existing file, it generally combines the file flags with the file attributes of the existing file, and ignores any file attributes supplied as part of dwFlagsAndAttributes. Special cases are detailed in Creating and Opening Files.

If you want to change the attributes of an existing file, AIUI that's SetFileAttributes. This gets exposed into Rust as File::set_permissions. We have a Unix PermissionsExt for low level manipulation, but no version for Windows.

If you can open/modify the file as you want to with the raw Win32 API, it should ideally be possible with the Rust std API, at least when using the OS specific extensions. If std doesn't expose the necessary knobs yet, it deserves an ACP to expose them as needed.

2 Likes

Hi,

The Microsoft docs suggest that the attributes being ignored when opening an existing file is a property of the Win32 API, not the Rust API

Thanks for the information, now I understand better why OpenOptions was not working.

This gets exposed into Rust as File::set_permissions. We have a Unix PermissionsExt for low level manipulation, but no version for Windows.

Well... That's exactly what my first message was about. Sorry if I wasn't clear. I do want to use std::fs::set_permissions (or File::set_permissions which I guess is equivalent), but type Permissions only exposes attribute "readonly" on Windows, whereas I need to set other attributes as well.

If std doesn't expose the necessary knobs yet, it deserves an ACP to expose them as needed.

How can I do an ACP? I thought this thread was already a sort of ACP.

Open an ACP issue on the libs-team repo

it's an attribute of every filesystem api i've worked with (plan9 and linux), which is probably why libstd is able to guarantee it.