mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-21 11:56:38 +00:00
fix(ecstore): gate rustix fs diagnostics on windows (#3267)
* fix(ecstore): gate rustix fs diagnostics on windows * fix(ecstore): improve windows disk validation diagnostics * build(deps): bump workspace dependency versions
This commit is contained in:
Generated
+308
-283
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -123,7 +123,7 @@ mysql_async = { version = "0.37", default-features = false, features = ["default
|
|||||||
async-compression = { version = "0.4.42" }
|
async-compression = { version = "0.4.42" }
|
||||||
async-recursion = "1.1.1"
|
async-recursion = "1.1.1"
|
||||||
async-trait = "0.1.89"
|
async-trait = "0.1.89"
|
||||||
async-nats = "0.49.0"
|
async-nats = "0.49.1"
|
||||||
axum = "0.8.9"
|
axum = "0.8.9"
|
||||||
futures = "0.3.32"
|
futures = "0.3.32"
|
||||||
futures-core = "0.3.32"
|
futures-core = "0.3.32"
|
||||||
@@ -157,7 +157,7 @@ bytesize = "2.3.1"
|
|||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
flatbuffers = "25.12.19"
|
flatbuffers = "25.12.19"
|
||||||
form_urlencoded = "1.2.2"
|
form_urlencoded = "1.2.2"
|
||||||
prost = "0.14.3"
|
prost = "0.14.4"
|
||||||
quick-xml = "0.40.1"
|
quick-xml = "0.40.1"
|
||||||
rmp = { version = "0.8.15" }
|
rmp = { version = "0.8.15" }
|
||||||
rmp-serde = { version = "1.3.1" }
|
rmp-serde = { version = "1.3.1" }
|
||||||
@@ -185,7 +185,7 @@ subtle = "2.6"
|
|||||||
zeroize = { version = "1.8.2", features = ["derive"] }
|
zeroize = { version = "1.8.2", features = ["derive"] }
|
||||||
|
|
||||||
# Time and Date
|
# Time and Date
|
||||||
chrono = { version = "0.4.44", features = ["serde"] }
|
chrono = { version = "0.4.45", features = ["serde"] }
|
||||||
humantime = "2.3.0"
|
humantime = "2.3.0"
|
||||||
jiff = { version = "0.2.28", features = ["serde"] }
|
jiff = { version = "0.2.28", features = ["serde"] }
|
||||||
time = { version = "0.3.47", features = ["std", "parsing", "formatting", "macros", "serde"] }
|
time = { version = "0.3.47", features = ["std", "parsing", "formatting", "macros", "serde"] }
|
||||||
@@ -199,7 +199,7 @@ tokio-postgres-rustls = "0.14.0"
|
|||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
arc-swap = "1.9.1"
|
arc-swap = "1.9.1"
|
||||||
astral-tokio-tar = "0.6.2"
|
astral-tokio-tar = "0.6.2"
|
||||||
atoi = "2.0.0"
|
atoi = "3.0.0"
|
||||||
atomic_enum = "0.3.0"
|
atomic_enum = "0.3.0"
|
||||||
aws-config = { version = "1.8.18" }
|
aws-config = { version = "1.8.18" }
|
||||||
aws-credential-types = { version = "1.2.14" }
|
aws-credential-types = { version = "1.2.14" }
|
||||||
@@ -223,8 +223,8 @@ enumset = "1.1.13"
|
|||||||
faster-hex = "0.10.0"
|
faster-hex = "0.10.0"
|
||||||
flate2 = "1.1.9"
|
flate2 = "1.1.9"
|
||||||
glob = "0.3.3"
|
glob = "0.3.3"
|
||||||
google-cloud-storage = "1.12.0"
|
google-cloud-storage = "1.14.0"
|
||||||
google-cloud-auth = "1.10.0"
|
google-cloud-auth = "1.12.0"
|
||||||
hashbrown = { version = "0.17.1", features = ["serde", "rayon"] }
|
hashbrown = { version = "0.17.1", features = ["serde", "rayon"] }
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
hex-simd = "0.8.0"
|
hex-simd = "0.8.0"
|
||||||
@@ -310,7 +310,7 @@ libunftp = { version = "0.23.0", features = ["experimental"] }
|
|||||||
unftp-core = "0.1.0"
|
unftp-core = "0.1.0"
|
||||||
suppaftp = { version = "8.0.3", features = ["tokio", "tokio-rustls-aws-lc-rs"] }
|
suppaftp = { version = "8.0.3", features = ["tokio", "tokio-rustls-aws-lc-rs"] }
|
||||||
rcgen = "0.14.8"
|
rcgen = "0.14.8"
|
||||||
russh = { version = "0.61.1",features = ["serde"] }
|
russh = { version = "0.61.2",features = ["serde"] }
|
||||||
russh-sftp = "2.3.0"
|
russh-sftp = "2.3.0"
|
||||||
|
|
||||||
# WebDAV
|
# WebDAV
|
||||||
|
|||||||
@@ -733,8 +733,13 @@ fn validate_local_physical_disk_independence(pools: &[Endpoints]) -> Result<()>
|
|||||||
match crate::disk::endpoint::windows_fallback_local_path(path, &err, "disk independence validation") {
|
match crate::disk::endpoint::windows_fallback_local_path(path, &err, "disk independence validation") {
|
||||||
Ok(absolute) => {
|
Ok(absolute) => {
|
||||||
let abs_path = absolute.to_string_lossy().into_owned();
|
let abs_path = absolute.to_string_lossy().into_owned();
|
||||||
|
diagnostic.canonical_path = Some(abs_path.clone());
|
||||||
|
if let Ok(serial) = rustfs_utils::os::get_volume_serial_number(&abs_path) {
|
||||||
|
diagnostic.device_numbers = Some(format!("serial:{serial:#010x}"));
|
||||||
|
}
|
||||||
match rustfs_utils::os::get_physical_device_ids(&abs_path) {
|
match rustfs_utils::os::get_physical_device_ids(&abs_path) {
|
||||||
Ok(ids) => {
|
Ok(ids) => {
|
||||||
|
diagnostic.device_ids = Some(ids.clone());
|
||||||
for device_id in ids {
|
for device_id in ids {
|
||||||
device_paths.entry(device_id).or_default().insert(abs_path.clone());
|
device_paths.entry(device_id).or_default().insert(abs_path.clone());
|
||||||
}
|
}
|
||||||
@@ -745,6 +750,7 @@ fn validate_local_physical_disk_independence(pools: &[Endpoints]) -> Result<()>
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(fallback_err) => {
|
Err(fallback_err) => {
|
||||||
@@ -769,9 +775,14 @@ fn validate_local_physical_disk_independence(pools: &[Endpoints]) -> Result<()>
|
|||||||
};
|
};
|
||||||
let canonical_path = canonical.to_string_lossy().into_owned();
|
let canonical_path = canonical.to_string_lossy().into_owned();
|
||||||
diagnostic.canonical_path = Some(canonical_path.clone());
|
diagnostic.canonical_path = Some(canonical_path.clone());
|
||||||
|
#[cfg(not(windows))]
|
||||||
if let Ok(stat) = rustix::fs::stat(canonical.as_path()) {
|
if let Ok(stat) = rustix::fs::stat(canonical.as_path()) {
|
||||||
diagnostic.device_numbers = Some(format!("{}:{}", rustix::fs::major(stat.st_dev), rustix::fs::minor(stat.st_dev)));
|
diagnostic.device_numbers = Some(format!("{}:{}", rustix::fs::major(stat.st_dev), rustix::fs::minor(stat.st_dev)));
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
if let Ok(serial) = rustfs_utils::os::get_volume_serial_number(&canonical_path) {
|
||||||
|
diagnostic.device_numbers = Some(format!("serial:{serial:#010x}"));
|
||||||
|
}
|
||||||
let device_ids = rustfs_utils::os::get_physical_device_ids(&canonical_path).map_err(|err| {
|
let device_ids = rustfs_utils::os::get_physical_device_ids(&canonical_path).map_err(|err| {
|
||||||
Error::other(format!("failed to inspect physical disk for local endpoint '{canonical_path}': {err}"))
|
Error::other(format!("failed to inspect physical disk for local endpoint '{canonical_path}': {err}"))
|
||||||
})?;
|
})?;
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ pub use linux::{check_cross_device_mounts, get_drive_stats, get_info, get_physic
|
|||||||
pub use unix::{check_cross_device_mounts, get_drive_stats, get_info, get_physical_device_ids, same_disk};
|
pub use unix::{check_cross_device_mounts, get_drive_stats, get_info, get_physical_device_ids, same_disk};
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub use windows::{check_cross_device_mounts, get_drive_stats, get_info, get_physical_device_ids, same_disk};
|
pub use windows::{
|
||||||
|
check_cross_device_mounts, get_drive_stats, get_info, get_physical_device_ids, get_volume_serial_number, same_disk,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq)]
|
#[derive(Debug, Default, PartialEq)]
|
||||||
pub struct IOStats {
|
pub struct IOStats {
|
||||||
|
|||||||
@@ -165,6 +165,42 @@ pub fn get_physical_device_ids(disk: &str) -> std::io::Result<Vec<String>> {
|
|||||||
Ok(vec![String::from_utf16_lossy(&volume)])
|
Ok(vec![String::from_utf16_lossy(&volume)])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the volume serial number for the filesystem backing `path`.
|
||||||
|
///
|
||||||
|
/// This is the Windows equivalent of Linux's `st_dev` major:minor pair and is
|
||||||
|
/// useful for diagnostic purposes when validating physical disk independence.
|
||||||
|
// SAFETY: `path_wide` is a valid null-terminated UTF-16 string and all output
|
||||||
|
// pointers target initialized stack variables with documented MAX_PATH sizing.
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
pub fn get_volume_serial_number(path: &str) -> std::io::Result<u32> {
|
||||||
|
let path_wide = to_wide_path(Path::new(path));
|
||||||
|
let volume = get_volume_name(&path_wide)?;
|
||||||
|
|
||||||
|
let mut volume_serial_number = 0u32;
|
||||||
|
let mut maximum_component_length = 0u32;
|
||||||
|
let mut file_system_flags = 0u32;
|
||||||
|
let mut volume_name_buffer = [0u16; MAX_PATH as usize];
|
||||||
|
let mut file_system_name_buffer = [0u16; MAX_PATH as usize];
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// 1. `volume` is a valid null-terminated UTF-16 string (volume root path).
|
||||||
|
// 2. Buffers are allocated with `MAX_PATH` size.
|
||||||
|
// 3. Pointers to output variables are valid.
|
||||||
|
unsafe {
|
||||||
|
GetVolumeInformationW(
|
||||||
|
windows::core::PCWSTR::from_raw(volume.as_ptr()),
|
||||||
|
Some(&mut volume_name_buffer),
|
||||||
|
Some(&mut volume_serial_number),
|
||||||
|
Some(&mut maximum_component_length),
|
||||||
|
Some(&mut file_system_flags),
|
||||||
|
Some(&mut file_system_name_buffer),
|
||||||
|
)
|
||||||
|
.map_err(|e| Error::from_raw_os_error(e.code().0))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(volume_serial_number)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_cross_device_mounts(_paths: &[String]) -> std::io::Result<()> {
|
pub fn check_cross_device_mounts(_paths: &[String]) -> std::io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user