Files
markbase/markbase-core/src/vfs/util.rs
Warren d94cb2df4c Fix code quality: trailing whitespace, unused imports, clippy warnings
- Fix trailing whitespace in kex.rs and s3.rs
- Add missing KexProposal import in kex_complete.rs
- Auto-fix clippy warnings across all crates
- All 153 tests pass
2026-06-19 05:21:38 +08:00

102 lines
3.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use super::{VfsError, VfsStat};
use chrono::Datelike;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
/// 从 std::io::ErrorKind 映射 VfsError
pub fn map_io_error(path: &Path, e: std::io::Error) -> VfsError {
match e.kind() {
std::io::ErrorKind::NotFound => VfsError::NotFound(path.display().to_string()),
std::io::ErrorKind::PermissionDenied => {
VfsError::PermissionDenied(path.display().to_string())
}
std::io::ErrorKind::AlreadyExists => VfsError::AlreadyExists(path.display().to_string()),
std::io::ErrorKind::DirectoryNotEmpty => VfsError::NotEmpty(path.display().to_string()),
std::io::ErrorKind::NotADirectory => VfsError::NotADirectory(path.display().to_string()),
std::io::ErrorKind::IsADirectory => VfsError::IsADirectory(path.display().to_string()),
std::io::ErrorKind::UnexpectedEof => VfsError::UnexpectedEof,
other => VfsError::Io(format!("{}: {}", other, path.display())),
}
}
/// 从 std::fs::Metadata 构建 VfsStat
pub fn stat_from_metadata(meta: &std::fs::Metadata, is_symlink: bool) -> VfsStat {
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
let mut stat = VfsStat::new();
stat.size = meta.len();
stat.is_dir = meta.is_dir();
stat.is_symlink = is_symlink;
#[cfg(unix)]
{
stat.mode = meta.permissions().mode();
stat.uid = meta.uid();
stat.gid = meta.gid();
}
#[cfg(not(unix))]
{
stat.mode = if meta.is_dir() { 0o40755 } else { 0o100644 };
}
if let Ok(t) = meta.accessed() {
stat.atime = t;
}
if let Ok(t) = meta.modified() {
stat.mtime = t;
}
stat
}
/// 构建目录条目的 long_name类似 ls -l 格式)
pub fn build_long_name(stat: &VfsStat, name: &str) -> String {
let file_type = if stat.is_dir { 'd' } else { '-' };
let perms = format_permissions(stat.mode & 0o777);
let link_count = if stat.is_dir { 3 } else { 1 };
let size = stat.size;
let mtime = match stat.mtime.duration_since(std::time::UNIX_EPOCH) {
Ok(d) => {
let secs = d.as_secs();
format_timestamp(secs)
}
Err(_) => "Jan 1 1970".to_string(),
};
format!(
"{}{} {} {} {} {} {} {}",
file_type, perms, link_count, stat.uid, stat.gid, size, mtime, name
)
}
fn format_permissions(mode: u32) -> String {
let rwx = |n: u32| -> String {
let r = if n & 4 != 0 { 'r' } else { '-' };
let w = if n & 2 != 0 { 'w' } else { '-' };
let x = if n & 1 != 0 { 'x' } else { '-' };
format!("{}{}{}", r, w, x)
};
format!(
"{}{}{}",
rwx((mode >> 6) & 7),
rwx((mode >> 3) & 7),
rwx(mode & 7)
)
}
fn format_timestamp(secs: u64) -> String {
let datetime = match chrono::DateTime::from_timestamp(secs as i64, 0) {
Some(dt) => dt,
None => return "Jan 1 1970".to_string(),
};
let now = chrono::Utc::now();
if datetime.year() == now.year() {
datetime.format("%b %e %H:%M").to_string()
} else {
datetime.format("%b %e %Y").to_string()
}
}