Skip to content

Commit 464d287

Browse files
joshwilhelmiclaude
andcommitted
[gobby-cli-#961] fix: stable Windows file-identity in gwiki log dedup
gwiki's windows-msvc release legs failed to compile: log::same_file_identity used std::os::windows::fs::MetadataExt::{file_index_high, file_index_low, volume_serial_number}, which sit behind the unstable `windows_by_handle` feature and do not exist on stable rustc (E0599/E0658). gwiki has never shipped Windows binaries — the windows-msvc targets were added to the matrix but the code was never stable-Windows-clean. Read the same volume-serial + file-index identity off the open file handle via GetFileInformationByHandle (windows-sys), preserving same_file_identity semantics (two paths are the same file iff equal (volume serial, file index high, file index low)). Promote windows-sys from a cfg(windows) dev-dependency to a real cfg(windows) dependency and add the Win32_Foundation feature for HANDLE. Host-validated: cargo build/clippy -p gobby-wiki, cargo fmt --all --check, and the log dedup tests pass. The windows-msvc compile is validated via the release-gwiki.yml workflow_dispatch dry-run (cannot cross-build Windows openssl/pdfium on macOS). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 933d78c commit 464d287

3 files changed

Lines changed: 32 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ follow-up indexing fixes.
9696
UTF-8 char boundary before the scoped link id is computed, so transcript links
9797
longer than the 8191-byte Postgres btree row limit no longer fail indexing
9898
atomically and strand orphan vault files (#939).
99+
- **Windows build**`gwiki` now compiles on `x86_64-pc-windows-msvc` /
100+
`aarch64-pc-windows-msvc`. The log de-duplication path read a file's
101+
volume-serial + file-index identity through the unstable `windows_by_handle`
102+
std accessors (nightly-only); it now reads the same fields via the stable
103+
`GetFileInformationByHandle` Win32 API, so the windows-msvc release legs build
104+
and `gwiki` ships Windows binaries for the first time (#961).
99105

100106
## [0.6.2] — ghook — 2026-06-26
101107

crates/gwiki/Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,11 @@ zip = { version = "4", default-features = false, features = ["deflate"], optiona
6464
[target.'cfg(unix)'.dependencies]
6565
libc = "0.2"
6666

67+
[target.'cfg(windows)'.dependencies]
68+
# Win32 file-identity in log.rs (GetFileInformationByHandle) plus symlink handling
69+
# in compile::tests::compile_rejects_target_page_through_symlinked_parent.
70+
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Storage_FileSystem"] }
71+
6772
[dev-dependencies]
6873
gobby-core = { path = "../gcore", version = "0.6.1", features = ["postgres", "falkor", "qdrant", "indexing", "search", "graph-analytics", "ai"] }
6974
serial_test = "3"
70-
71-
[target.'cfg(windows)'.dev-dependencies]
72-
# Reserved for Windows symlink handling in compile::tests::compile_rejects_target_page_through_symlinked_parent.
73-
windows-sys = { version = "0.61", features = ["Win32_Storage_FileSystem"] }

crates/gwiki/src/log.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,18 +128,33 @@ fn same_file_identity(left: &Path, right: &Path) -> bool {
128128
}
129129

130130
#[cfg(windows)]
131+
#[allow(dead_code, reason = "reserved gwiki CLI/API split")]
131132
fn same_file_identity(left: &Path, right: &Path) -> bool {
132-
use std::os::windows::fs::MetadataExt;
133+
use std::os::windows::io::AsRawHandle;
134+
use windows_sys::Win32::Foundation::HANDLE;
135+
use windows_sys::Win32::Storage::FileSystem::{
136+
BY_HANDLE_FILE_INFORMATION, GetFileInformationByHandle,
137+
};
133138

134139
fn identity(path: &Path) -> Option<(u32, u32, u32)> {
135-
let metadata = std::fs::metadata(path).ok()?;
136-
if metadata.file_index_high() == 0 && metadata.file_index_low() == 0 {
140+
// The std MetadataExt accessors for volume serial + file index are still
141+
// unstable (windows_by_handle), so read them off the open file handle
142+
// via GetFileInformationByHandle to stay on stable Rust.
143+
let file = std::fs::File::open(path).ok()?;
144+
let mut info: BY_HANDLE_FILE_INFORMATION = unsafe { std::mem::zeroed() };
145+
// SAFETY: `file` owns a valid handle for the duration of the call, and
146+
// `info` is a properly aligned, writable output buffer.
147+
let ok = unsafe { GetFileInformationByHandle(file.as_raw_handle() as HANDLE, &mut info) };
148+
if ok == 0 {
149+
return None;
150+
}
151+
if info.nFileIndexHigh == 0 && info.nFileIndexLow == 0 {
137152
return None;
138153
}
139154
Some((
140-
metadata.volume_serial_number(),
141-
metadata.file_index_high(),
142-
metadata.file_index_low(),
155+
info.dwVolumeSerialNumber,
156+
info.nFileIndexHigh,
157+
info.nFileIndexLow,
143158
))
144159
}
145160

0 commit comments

Comments
 (0)