diff --git a/Cargo.lock b/Cargo.lock index 0f0546005b..20d9ea6c51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3678,6 +3678,7 @@ dependencies = [ "text", "time", "util", + "windows-sys 0.52.0", ] [[package]] diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml index d3f6d87d30..67f0ad47ff 100644 --- a/crates/fs/Cargo.toml +++ b/crates/fs/Cargo.toml @@ -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"] } diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index bde0fe3f70..6452b08127 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -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) -> Result { + 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::*;