diff --git a/crates/ecstore/src/disk/local.rs b/crates/ecstore/src/disk/local.rs index dd5dc8c67..17d4e3579 100644 --- a/crates/ecstore/src/disk/local.rs +++ b/crates/ecstore/src/disk/local.rs @@ -26,10 +26,7 @@ use crate::disk::{ error::{DiskError, Error, FileAccessDeniedWithContext, Result}, error_conv::{to_access_error, to_file_error, to_unformatted_disk_error, to_volume_error}, format::FormatV3, - fs::{ - O_APPEND, O_CREATE, O_RDONLY, O_TRUNC, O_WRONLY, access, access_std, lstat, lstat_std, remove, remove_all_std, - remove_std, rename, - }, + fs::{O_APPEND, O_CREATE, O_RDONLY, O_TRUNC, O_WRONLY, access, lstat, lstat_std, remove, remove_all_std, remove_std, rename}, os, os::{check_path_length, is_empty_dir, is_root_disk, rename_all, rename_all_ignore_missing_source}, }; @@ -101,7 +98,7 @@ fn inline_metadata_rollback_dir(version_id: Uuid, meta: &FileMeta) -> Uuid { fn remove_file_if_exists(path: &Path) -> std::io::Result<()> { match std::fs::remove_file(path) { Ok(()) => Ok(()), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()), + Err(err) if err.kind() == ErrorKind::NotFound => Ok(()), Err(err) => Err(err), } } @@ -109,7 +106,7 @@ fn remove_file_if_exists(path: &Path) -> std::io::Result<()> { fn remove_dir_all_if_exists(path: &Path) -> std::io::Result<()> { match std::fs::remove_dir_all(path) { Ok(()) => Ok(()), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()), + Err(err) if err.kind() == ErrorKind::NotFound => Ok(()), Err(err) => Err(err), } } @@ -121,7 +118,7 @@ fn rollback_committed_rename_std( ) -> std::io::Result<()> { if let Some(old_data_dir) = rollback_data_dir { let Some(dst_parent) = dst_file_path.parent() else { - return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "missing object metadata parent")); + return Err(std::io::Error::new(ErrorKind::InvalidInput, "missing object metadata parent")); }; let backup_path = dst_parent.join(old_data_dir.to_string()).join(STORAGE_FORMAT_FILE_BACKUP); std::fs::rename(backup_path, dst_file_path)?; @@ -591,7 +588,7 @@ impl DurabilityMode { "strict" => Some(Self::Strict), "relaxed" => Some(Self::Relaxed), "none" => Some(Self::None), - _ => Option::None, + _ => None, } } @@ -799,7 +796,7 @@ pub(crate) mod bucket_durability { /// configured durability mode: their contents commit into user buckets and /// are exactly the writes the relaxed tiers exist for. fn is_scratch_volume(volume: &str) -> bool { - for scratch in [super::RUSTFS_META_TMP_BUCKET, super::RUSTFS_META_MULTIPART_BUCKET] { + for scratch in [RUSTFS_META_TMP_BUCKET, super::RUSTFS_META_MULTIPART_BUCKET] { if volume == scratch || volume.strip_prefix(scratch).is_some_and(|rest| rest.starts_with('/')) { return true; } @@ -816,7 +813,7 @@ fn is_system_critical_volume(volume: &str) -> bool { if is_scratch_volume(volume) { return false; } - for meta in [super::RUSTFS_META_BUCKET, super::MIGRATING_META_BUCKET] { + for meta in [RUSTFS_META_BUCKET, super::MIGRATING_META_BUCKET] { if volume == meta || volume.strip_prefix(meta).is_some_and(|rest| rest.starts_with('/')) { return true; } @@ -935,12 +932,12 @@ struct AlignedBuf { impl AlignedBuf { fn new(len: usize, align: usize) -> std::io::Result { debug_assert!(len > 0, "AlignedBuf must not be zero-sized"); - let layout = std::alloc::Layout::from_size_align(len, align) - .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?; + let layout = + std::alloc::Layout::from_size_align(len, align).map_err(|e| std::io::Error::new(ErrorKind::InvalidInput, e))?; // SAFETY: `layout` has non-zero size (callers guarantee len > 0) and a // valid power-of-two alignment enforced by Layout::from_size_align. let ptr = unsafe { std::alloc::alloc_zeroed(layout) }; - let ptr = std::ptr::NonNull::new(ptr).ok_or(std::io::ErrorKind::OutOfMemory)?; + let ptr = std::ptr::NonNull::new(ptr).ok_or(ErrorKind::OutOfMemory)?; Ok(Self { ptr, len, layout }) } @@ -994,10 +991,9 @@ fn pread_direct_aligned(file_path: &Path, offset: u64, length: usize, state: &Di let align_u64 = align as u64; let aligned_offset = offset - (offset % align_u64); - let logical_start = - usize::try_from(offset - aligned_offset).map_err(|_| std::io::Error::from(std::io::ErrorKind::InvalidInput))?; - let logical_end = logical_start.checked_add(length).ok_or(std::io::ErrorKind::InvalidInput)?; - let aligned_len = logical_end.checked_add(align - 1).ok_or(std::io::ErrorKind::InvalidInput)? / align * align; + let logical_start = usize::try_from(offset - aligned_offset).map_err(|_| std::io::Error::from(ErrorKind::InvalidInput))?; + let logical_end = logical_start.checked_add(length).ok_or(ErrorKind::InvalidInput)?; + let aligned_len = logical_end.checked_add(align - 1).ok_or(ErrorKind::InvalidInput)? / align * align; let mut buf = AlignedBuf::new(aligned_len, align)?; @@ -1012,7 +1008,7 @@ fn pread_direct_aligned(file_path: &Path, offset: u64, length: usize, state: &Di filled += n; } if filled < logical_end { - return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "short O_DIRECT read")); + return Err(std::io::Error::new(ErrorKind::UnexpectedEof, "short O_DIRECT read")); } Ok(Bytes::copy_from_slice(&buf.as_slice()[logical_start..logical_end])) @@ -1094,10 +1090,7 @@ fn pwrite_all(file: &std::fs::File, mut buf: &[u8], mut offset: u64) -> std::io: while !buf.is_empty() { let n = file.write_at(buf, offset)?; if n == 0 { - return Err(std::io::Error::new( - std::io::ErrorKind::WriteZero, - "O_DIRECT positioned write wrote 0 bytes", - )); + return Err(std::io::Error::new(ErrorKind::WriteZero, "O_DIRECT positioned write wrote 0 bytes")); } buf = &buf[n..]; offset += n as u64; @@ -2128,7 +2121,8 @@ impl LocalIoBackend for StdBackend { let access_check_start = metrics_enabled.then(StdInstant::now); let volume_dir = local_disk_bucket_path(&root, &volume_owned)?; if !skip_access_checks(&volume_owned) { - access_std(&volume_dir).map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?; + crate::disk::fs::access_std(&volume_dir) + .map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?; } let access_check_duration = access_check_start.map_or(StdDuration::ZERO, |started_at| started_at.elapsed()); @@ -2948,7 +2942,8 @@ fn is_io_uring_unsupported(err: &std::io::Error) -> bool { fn resolve_uring_object_path(root: &Path, volume: &str, path: &str) -> Result { let volume_dir = local_disk_bucket_path(root, volume)?; if !skip_access_checks(volume) { - access_std(&volume_dir).map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?; + crate::disk::fs::access_std(&volume_dir) + .map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?; } let file_path = local_disk_object_path(root, volume, path)?; check_path_length(file_path.to_string_lossy().as_ref())?; @@ -3797,10 +3792,9 @@ impl LocalDisk { // rebuilding (see rustfs-heal); surface it so scanner // coordination, lock selection and admin/metrics see // the rebuild. Refreshed with this cache (~1s). - let healing = - tokio::fs::try_exists(root.join(super::RUSTFS_META_BUCKET).join(super::HEALING_MARKER_PATH)) - .await - .unwrap_or(false); + let healing = tokio::fs::try_exists(root.join(RUSTFS_META_BUCKET).join(super::HEALING_MARKER_PATH)) + .await + .unwrap_or(false); let disk_info = DiskInfo { total: info.total, free: info.free, @@ -4780,8 +4774,8 @@ impl LocalDisk { let file_path = self.get_object_path(volume, path)?; check_path_length(file_path.to_string_lossy().as_ref())?; - let tmp_volume_dir = self.get_bucket_path(super::RUSTFS_META_TMP_BUCKET)?; - let tmp_file_path = self.get_object_path(super::RUSTFS_META_TMP_BUCKET, Uuid::new_v4().to_string().as_str())?; + let tmp_volume_dir = self.get_bucket_path(RUSTFS_META_TMP_BUCKET)?; + let tmp_file_path = self.get_object_path(RUSTFS_META_TMP_BUCKET, Uuid::new_v4().to_string().as_str())?; let durability = effective_durability(volume); @@ -5641,7 +5635,7 @@ async fn read_file_metadata(p: impl AsRef) -> Result { fn skip_access_checks(p: impl AsRef) -> bool { let vols = [ RUSTFS_META_TMP_DELETED_BUCKET, - super::RUSTFS_META_TMP_BUCKET, + RUSTFS_META_TMP_BUCKET, super::RUSTFS_META_MULTIPART_BUCKET, RUSTFS_META_BUCKET, ]; @@ -5952,12 +5946,11 @@ impl DiskAPI for LocalDisk { ); for (i, part) in fi.parts.iter().enumerate() { let checksum_info = erasure.get_checksum_info(part.number); - let checksum_algo = - if fi.uses_legacy_checksum && checksum_info.algorithm == rustfs_utils::HashAlgorithm::HighwayHash256S { - rustfs_utils::HashAlgorithm::HighwayHash256SLegacy - } else { - checksum_info.algorithm - }; + let checksum_algo = if fi.uses_legacy_checksum && checksum_info.algorithm == HashAlgorithm::HighwayHash256S { + HashAlgorithm::HighwayHash256SLegacy + } else { + checksum_info.algorithm + }; let part_path = self.get_object_path( volume, path_join_buf(&[ @@ -6985,7 +6978,7 @@ impl DiskAPI for LocalDisk { // Read existing xl.meta let has_dst_buf = match std::fs::read(&dst) { Ok(buf) => Some(Bytes::from(buf)), - Err(e) if e.kind() == std::io::ErrorKind::NotFound => None, + Err(e) if e.kind() == ErrorKind::NotFound => None, Err(e) => return Err(to_file_error(e)), }; @@ -7077,8 +7070,8 @@ impl DiskAPI for LocalDisk { match std::fs::rename(&src, &dst) { Ok(()) => Ok(()), - Err(err) if err.kind() == std::io::ErrorKind::NotFound && !src.exists() => Ok(()), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + Err(err) if err.kind() == ErrorKind::NotFound && !src.exists() => Ok(()), + Err(err) if err.kind() == ErrorKind::NotFound => { if let Some(parent) = dst.parent() { std::fs::create_dir_all(parent)?; } @@ -7126,7 +7119,7 @@ impl DiskAPI for LocalDisk { } } - Ok::<(Option, Option>, Option), std::io::Error>(( + Ok::<(Option, Option>, Option), std::io::Error>(( rollback_data_dir, version_signature, old_current_size, @@ -8110,7 +8103,7 @@ mod test { /// Crash-consistency harness for the rename_data commit sequence /// (rustfs/backlog#935 HP-14, test plan rustfs/backlog#896; hard rule from - /// rustfs/backlog#878: "partial commit 后对象只能是旧版本或新版本,不能混合"). + /// rustfs/backlog#878: "After partial commit, the object can only be an old or new version; it cannot be mixed"). /// /// For every pre-commit crash point × durability tier, it seeds a committed /// object, stages a replacement, injects a hard power loss (no in-process @@ -8449,7 +8442,7 @@ mod test { /// Backdate a path's mtime so zero-expiry cleanup tests classify it as /// stale deterministically, instead of sleeping and hoping the filesystem /// timestamp granularity (or a backward wall-clock step) cooperates. - fn backdate_mtime(path: &std::path::Path, age: Duration) { + fn backdate_mtime(path: &Path, age: Duration) { use std::fs::{File, FileTimes}; let mtime = std::time::SystemTime::now() - age; File::open(path) @@ -8858,17 +8851,13 @@ mod test { async fn blocking_scan_writer_keeps_flush_and_shutdown_pending() { let mut flush_writer = BlockingScanWriter { entered_tx: None }; assert!( - tokio::time::timeout(Duration::from_millis(10), flush_writer.flush()) - .await - .is_err(), + timeout(Duration::from_millis(10), flush_writer.flush()).await.is_err(), "blocking scan writer flush should stay pending" ); let mut shutdown_writer = BlockingScanWriter { entered_tx: None }; assert!( - tokio::time::timeout(Duration::from_millis(10), shutdown_writer.shutdown()) - .await - .is_err(), + timeout(Duration::from_millis(10), shutdown_writer.shutdown()).await.is_err(), "blocking scan writer shutdown should stay pending" ); } @@ -8877,15 +8866,11 @@ mod test { /// consumer (quorum merge, a lagging peer drive). struct SlowWriter { delay: Duration, - sleep: Option>>, + sleep: Option>>, } impl AsyncWrite for SlowWriter { - fn poll_write( - mut self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - buf: &[u8], - ) -> std::task::Poll> { + fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { if self.sleep.is_none() { let delay = self.delay; self.sleep = Some(Box::pin(tokio::time::sleep(delay))); @@ -8893,23 +8878,20 @@ mod test { let sleep = self.sleep.as_mut().expect("sleep was just installed"); match sleep.as_mut().poll(cx) { - std::task::Poll::Ready(()) => { + Poll::Ready(()) => { self.sleep = None; - std::task::Poll::Ready(Ok(buf.len())) + Poll::Ready(Ok(buf.len())) } - std::task::Poll::Pending => std::task::Poll::Pending, + Poll::Pending => Poll::Pending, } } - fn poll_flush(self: std::pin::Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> std::task::Poll> { - std::task::Poll::Ready(Ok(())) + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) } - fn poll_shutdown( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(())) + fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) } } @@ -9605,14 +9587,14 @@ mod test { bucket_durability::set(super::super::RUSTFS_META_MULTIPART_BUCKET, Some(DurabilityMode::Relaxed)); bucket_durability::set("", Some(DurabilityMode::Relaxed)); - assert_eq!(bucket_durability::lookup(RUSTFS_META_BUCKET), Option::None); - assert_eq!(bucket_durability::lookup(RUSTFS_META_TMP_BUCKET), Option::None); + assert_eq!(bucket_durability::lookup(RUSTFS_META_BUCKET), None); + assert_eq!(bucket_durability::lookup(RUSTFS_META_TMP_BUCKET), None); assert_eq!(effective_durability(RUSTFS_META_BUCKET), DurabilityMode::Strict); // The legacy full-off tier is process-wide only: registering it per // bucket is dropped, not stored. bucket_durability::set("hp5b-legacy-refused", Some(DurabilityMode::LegacyOff)); - assert_eq!(bucket_durability::lookup("hp5b-legacy-refused"), Option::None); + assert_eq!(bucket_durability::lookup("hp5b-legacy-refused"), None); } #[test] @@ -11071,7 +11053,7 @@ mod test { let vols = [ RUSTFS_META_TMP_DELETED_BUCKET, - super::super::RUSTFS_META_TMP_BUCKET, + RUSTFS_META_TMP_BUCKET, super::super::RUSTFS_META_MULTIPART_BUCKET, RUSTFS_META_BUCKET, ]; @@ -11110,7 +11092,7 @@ mod test { let mut reader = StallTimeoutReader::new(PendingTestReader, Duration::ZERO); let mut buf = [0; 1]; - let result = tokio::time::timeout(Duration::from_millis(10), reader.read(&mut buf)).await; + let result = timeout(Duration::from_millis(10), reader.read(&mut buf)).await; assert!(result.is_err(), "zero timeout must leave stalled reads pending instead of failing"); } @@ -11240,10 +11222,10 @@ mod test { #[tokio::test(start_paused = true)] async fn cleanup_loop_interval_does_not_tick_immediately() { - let start_at = tokio::time::Instant::now() + DELETED_OBJECTS_CLEANUP_INTERVAL; + let start_at = Instant::now() + DELETED_OBJECTS_CLEANUP_INTERVAL; let mut interval = interval_at(start_at, DELETED_OBJECTS_CLEANUP_INTERVAL); - assert!(tokio::time::timeout(Duration::from_secs(1), interval.tick()).await.is_err()); + assert!(timeout(Duration::from_secs(1), interval.tick()).await.is_err()); tokio::time::advance(DELETED_OBJECTS_CLEANUP_INTERVAL).await; interval.tick().await; @@ -11291,26 +11273,16 @@ mod test { struct BrokenPipeWriter; impl AsyncWrite for BrokenPipeWriter { - fn poll_write( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - _buf: &[u8], - ) -> std::task::Poll> { - std::task::Poll::Ready(Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, "closed"))) + fn poll_write(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &[u8]) -> Poll> { + Poll::Ready(Err(io::Error::new(ErrorKind::BrokenPipe, "closed"))) } - fn poll_flush( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(())) + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) } - fn poll_shutdown( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(())) + fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) } } @@ -12442,7 +12414,7 @@ mod test { fs::set_permissions(&meta_path, Permissions::from_mode(0o000)) .await .expect("operation should succeed"); - if fs::File::open(&meta_path).await.is_ok() { + if File::open(&meta_path).await.is_ok() { fs::set_permissions(&meta_path, original_permissions) .await .expect("operation should succeed"); @@ -12977,7 +12949,7 @@ mod test { // It only checks length and platform-specific special characters // System volume names are valid according to the current implementation assert!(LocalDisk::is_valid_volname(RUSTFS_META_BUCKET)); - assert!(LocalDisk::is_valid_volname(super::super::RUSTFS_META_TMP_BUCKET)); + assert!(LocalDisk::is_valid_volname(RUSTFS_META_TMP_BUCKET)); // Testing platform-specific behavior for special characters #[cfg(windows)] @@ -13321,24 +13293,20 @@ mod test { #[cfg(unix)] { - for (kind, expected) in [("minor", 1), ("major", 2)] { + for (kind, expected) in [("minor", 1), ("major", 2)].iter().copied() { + let labels = [("path", "local_test"), ("stage", "mmap_map"), ("kind", kind)]; assert_eq!( - recorder.counter_value( - METRIC_GET_OBJECT_MMAP_PAGE_FAULTS_TOTAL, - &[("path", "local_test"), ("stage", "mmap_map"), ("kind", kind)] - ), + recorder.counter_value(METRIC_GET_OBJECT_MMAP_PAGE_FAULTS_TOTAL, &labels), expected, - "zero deltas must not emit and positive {kind} deltas must accumulate exactly" + "zero deltas must not emit and positive mmap page fault deltas must accumulate exactly" ); } - for (kind, expected) in [("minor", 3), ("major", 4)] { + for (kind, expected) in [("minor", 3), ("major", 4)].iter().copied() { + let labels = [("path", "local_test"), ("stage", "direct_read_copy"), ("kind", kind)]; assert_eq!( - recorder.counter_value( - METRIC_GET_OBJECT_DIRECT_READ_PAGE_FAULTS_TOTAL, - &[("path", "local_test"), ("stage", "direct_read_copy"), ("kind", kind)] - ), + recorder.counter_value(METRIC_GET_OBJECT_DIRECT_READ_PAGE_FAULTS_TOTAL, &labels), expected, - "zero deltas must not emit and positive {kind} deltas must accumulate exactly" + "zero deltas must not emit and positive direct-read page fault deltas must accumulate exactly" ); } } @@ -13553,15 +13521,15 @@ mod test { #[test] fn test_is_bitrot_size_mismatch_error_only_matches_target_message() { - assert!(is_bitrot_size_mismatch_error(&std::io::Error::other("bitrot shard file size mismatch"))); - assert!(!is_bitrot_size_mismatch_error(&std::io::Error::other("bitrot hash mismatch"))); + assert!(is_bitrot_size_mismatch_error(&io::Error::other("bitrot shard file size mismatch"))); + assert!(!is_bitrot_size_mismatch_error(&io::Error::other("bitrot hash mismatch"))); } #[test] fn test_is_bitrot_verification_error_matches_hash_and_size_mismatch() { - assert!(is_bitrot_verification_error(&std::io::Error::other("bitrot shard file size mismatch"))); - assert!(is_bitrot_verification_error(&std::io::Error::other("bitrot hash mismatch"))); - assert!(!is_bitrot_verification_error(&std::io::Error::other("unrelated io failure"))); + assert!(is_bitrot_verification_error(&io::Error::other("bitrot shard file size mismatch"))); + assert!(is_bitrot_verification_error(&io::Error::other("bitrot hash mismatch"))); + assert!(!is_bitrot_verification_error(&io::Error::other("unrelated io failure"))); } #[tokio::test] @@ -13600,7 +13568,7 @@ mod test { ..Default::default() }]; - let mut writer = BitrotWriter::new(std::io::Cursor::new(Vec::new()), file_info.erasure.shard_size(), checksum_algo); + let mut writer = BitrotWriter::new(io::Cursor::new(Vec::new()), file_info.erasure.shard_size(), checksum_algo); writer .write(&payload) .await @@ -13667,7 +13635,7 @@ mod test { } else { HashAlgorithm::HighwayHash256S }; - let mut writer = BitrotWriter::new(std::io::Cursor::new(Vec::new()), codec_erasure.shard_size(), checksum_algo); + let mut writer = BitrotWriter::new(io::Cursor::new(Vec::new()), codec_erasure.shard_size(), checksum_algo); writer.write(&payload[..8]).await.expect("first shard block should encode"); writer.write(&payload[8..]).await.expect("final shard block should encode"); writer.shutdown().await.expect("bitrot writer should flush test payload"); @@ -14524,7 +14492,7 @@ mod test { // SAFETY: `map.as_ptr()` is page-aligned and `len` bytes long; `vec` has // one byte per page of that range, which is what mincore writes. let rc = unsafe { libc::mincore(map.as_ptr() as *mut libc::c_void, len, vec.as_mut_ptr()) }; - assert_eq!(rc, 0, "mincore failed: {}", std::io::Error::last_os_error()); + assert_eq!(rc, 0, "mincore failed: {}", io::Error::last_os_error()); vec.iter().filter(|b| *b & 1 == 1).count() } diff --git a/crates/kms/src/backends/local.rs b/crates/kms/src/backends/local.rs index a82cac7cc..6b483de31 100644 --- a/crates/kms/src/backends/local.rs +++ b/crates/kms/src/backends/local.rs @@ -157,8 +157,8 @@ impl LocalKmsClient { Ok(salt) } + #[cfg(unix)] async fn set_file_permissions(path: &std::path::Path, permissions: Option) -> Result<()> { - #[cfg(unix)] if let Some(mode) = permissions { use std::os::unix::fs::PermissionsExt; @@ -166,7 +166,11 @@ impl LocalKmsClient { fs::set_permissions(path, perms).await?; } - let _ = permissions; + Ok(()) + } + + #[cfg(not(unix))] + async fn set_file_permissions(_path: &std::path::Path, _permissions: Option) -> Result<()> { Ok(()) }