mirror of
https://github.com/nimbold/Firelink.git
synced 2026-09-02 05:57:59 +00:00
fix(ci): repair cross-platform native checks
- make cleanup tests configure an explicit approved root instead of relying on platform download-directory discovery - replace unstable Windows metadata extensions with stable Win32 file identity lookup - preserve exact replacement fingerprint validation across enqueue, quarantine, recovery, and cleanup paths
This commit is contained in:
@@ -2,6 +2,58 @@ use std::ffi::OsString;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Return a stable filesystem identity for an existing Windows file without
|
||||
/// relying on unstable `std::fs::MetadataExt` APIs. The handle is opened with
|
||||
/// delete sharing so inspection does not unnecessarily block normal cleanup
|
||||
/// or replacement; callers still validate the path with `symlink_metadata`
|
||||
/// before using this identity.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn file_identity(path: &Path) -> Option<String> {
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
CreateFileW, GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION, FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
|
||||
OPEN_EXISTING,
|
||||
};
|
||||
|
||||
let wide_path = path
|
||||
.as_os_str()
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect::<Vec<_>>();
|
||||
// A zero desired-access mask requests metadata access only. Opening with
|
||||
// all sharing flags avoids introducing a lock that changes the outcome of
|
||||
// a subsequent exact replacement or cleanup operation.
|
||||
let handle = unsafe {
|
||||
CreateFileW(
|
||||
wide_path.as_ptr(),
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
std::ptr::null(),
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
0,
|
||||
)
|
||||
};
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut metadata = BY_HANDLE_FILE_INFORMATION::default();
|
||||
let result = unsafe {
|
||||
let succeeded = GetFileInformationByHandle(handle, &mut metadata) != 0;
|
||||
let _ = CloseHandle(handle);
|
||||
succeeded
|
||||
};
|
||||
result.then(|| {
|
||||
format!(
|
||||
"{}:{}:{}",
|
||||
metadata.dwVolumeSerialNumber, metadata.nFileIndexHigh, metadata.nFileIndexLow
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const ATOMIC_TEMP_PREFIX: &str = ".firelink-atomic-";
|
||||
|
||||
/// Write bytes to a same-directory temporary file, synchronize them, and
|
||||
|
||||
Reference in New Issue
Block a user