Introduce file_id on Windows (#8130)

Added a function `file_id` to get the file id on windows, which is
similar to inode on unix.

Release Notes:

- N/A
This commit is contained in:
Small White 2024-02-23 03:22:12 +08:00 committed by GitHub
parent 991c9ec441
commit a475d8640f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 44 additions and 3 deletions

1
Cargo.lock generated
View File

@ -3678,6 +3678,7 @@ dependencies = [
"text",
"time",
"util",
"windows-sys 0.52.0",
]
[[package]]

View File

@ -32,11 +32,17 @@ log.workspace = true
libc = "0.2"
time.workspace = true
gpui = { workspace = true, optional = true}
gpui = { workspace = true, optional = true }
[target.'cfg(not(target_os = "macos"))'.dependencies]
notify = "6.1.1"
[target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { version = "0.52", features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",
] }
[dev-dependencies]
gpui = { workspace = true, features = ["test-support"] }

View File

@ -245,9 +245,8 @@ impl Fs for RealFs {
#[cfg(unix)]
let inode = metadata.ino();
// todo!("windows")
#[cfg(windows)]
let inode = 0;
let inode = file_id(path).await?;
Ok(Some(Metadata {
inode,
@ -1337,6 +1336,41 @@ pub fn copy_recursive<'a>(
.boxed()
}
// todo!(windows)
// can we get file id not open the file twice?
// https://github.com/rust-lang/rust/issues/63010
#[cfg(target_os = "windows")]
async fn file_id(path: impl AsRef<Path>) -> Result<u64> {
use std::os::windows::io::AsRawHandle;
use smol::fs::windows::OpenOptionsExt;
use windows_sys::Win32::{
Foundation::HANDLE,
Storage::FileSystem::{
GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION, FILE_FLAG_BACKUP_SEMANTICS,
},
};
let file = smol::fs::OpenOptions::new()
.read(true)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.open(path)
.await?;
let mut info: BY_HANDLE_FILE_INFORMATION = unsafe { std::mem::zeroed() };
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
// This function supports Windows XP+
smol::unblock(move || {
let ret = unsafe { GetFileInformationByHandle(file.as_raw_handle() as HANDLE, &mut info) };
if ret == 0 {
return Err(anyhow!(format!("{}", std::io::Error::last_os_error())));
};
Ok(((info.nFileIndexHigh as u64) << 32) | (info.nFileIndexLow as u64))
})
.await
}
#[cfg(test)]
mod tests {
use super::*;