Description
I tried this code:
use std::path::Path;
use std::env::args_os;
fn main() {
let p = args_os().skip(1).next().expect("to have a path argument");
let p: &Path = p.as_ref();
dbg!(p.display());
dbg!(p.exists());
dbg!(p.metadata());
dbg!(p.symlink_metadata());
dbg!(p.is_file());
dbg!(p.is_dir());
dbg!(p.is_symlink());
}
I expected to see this happen:
The API should report the given path exists.
Instead, this happened:
When passed a path to a UNIX domain socket on Windows, I get:
[src\main.rs:22] p.display() = "<REDACTED>\\socket"
[src\main.rs:23] p.exists() = false
[src\main.rs:24] p.metadata() = Err(
Os {
code: 1920,
kind: Uncategorized,
message: "The file cannot be accessed by the system.",
},
)
[src\main.rs:25] p.symlink_metadata() = Ok(
Metadata {
file_type: FileType(
FileType {
attributes: 1056,
reparse_tag: 2147483683,
},
),
is_dir: false,
is_file: true,
permissions: Permissions(
FilePermissions {
attrs: 1056,
},
),
modified: Ok(
SystemTime {
intervals: 133232173107398736,
},
),
accessed: Ok(
SystemTime {
intervals: 133232173107398736,
},
),
created: Ok(
SystemTime {
intervals: 133172157242066860,
},
),
..
},
)
[src\main.rs:26] p.is_file() = false
[src\main.rs:27] p.is_dir() = false
[src\main.rs:28] p.is_symlink() = false
Meta
rustc --version --verbose
:
rustc --version --verbose
rustc 1.68.0 (2c8cc3432 2023-03-06)
binary: rustc
commit-hash: 2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74
commit-date: 2023-03-06
host: x86_64-pc-windows-msvc
release: 1.68.0
LLVM version: 15.0.6
Analysis
I think this is simply an unintended consequence of supporting symlinks on Windows. It is interesting that symlink_metadata
seems to be producing a correct result here (IMO this metadata should be returned by metadata()
).
The differences between stat
(metadata
) and lstat
(symlink_metadata
) is the ReparsePoint
flag.
rust/library/std/src/sys/windows/fs.rs
Lines 1152 to 1158 in 8d4adad
On Windows, UNIX domain sockets are implemented as reparse points just like symlink. However Rust is only setting the FILE_FLAG_OPEN_REPARSE_POINT
flag when we are testing for symlink. Without this flag CreateFileW
is going to return the access error above.
I think the issue is that, the standard library didn't consider that the possibility to have other type of files that are reparse points but not symlinks.
I'm not sure what is the best fix for this, but this is kinda surprising.