From 30186c23fbd585f4e9002633636b50c9a83b7de5 Mon Sep 17 00:00:00 2001 From: licsber Date: Fri, 8 May 2026 00:18:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20[#1932]=20l-s=20v0.5.1=20=E5=8E=9F?= =?UTF-8?q?=E5=AD=90=E5=86=99=E5=85=A5=E4=BF=9D=E6=8A=A4=E5=8F=8A=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 169 ++++++++++++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 8 +- src/main.rs | 50 +++++++++++-- src/meta/file.rs | 12 ++- src/meta/progress.rs | 20 +++-- src/meta/tree.rs | 19 ++--- src/utils.rs | 8 +- 8 files changed, 193 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7feb365..c45c3cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -19,15 +19,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "block-buffer" @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "cfg-if" @@ -81,9 +81,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.53" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -91,9 +91,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -115,25 +115,24 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "console" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" dependencies = [ "encode_unicode", "libc", - "once_cell", "unicode-width", "windows-sys", ] @@ -183,6 +182,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -201,9 +224,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indicatif" -version = "0.18.3" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" dependencies = [ "console", "portable-atomic", @@ -220,23 +243,25 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] [[package]] name = "l-s" -version = "0.5.0" +version = "0.5.1" dependencies = [ "anyhow", "clap", @@ -252,9 +277,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.178" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "md-5" @@ -277,15 +302,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -294,25 +319,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "portable-atomic" -version = "1.12.0" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f59e70c4aef1e55797c2e8fd94a4f2a973fc972cfde0e0b05f683667b0cd39dd" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -323,12 +354,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea" - [[package]] name = "serde" version = "1.0.228" @@ -361,15 +386,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -394,6 +419,12 @@ dependencies = [ "digest", ] +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "strsim" version = "0.11.1" @@ -402,9 +433,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.111" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -413,15 +444,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-width" @@ -449,9 +480,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" dependencies = [ "cfg-if", "once_cell", @@ -462,9 +493,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -472,9 +503,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" dependencies = [ "bumpalo", "proc-macro2", @@ -485,9 +516,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" dependencies = [ "unicode-ident", ] @@ -522,3 +553,9 @@ name = "xxhash-rust" version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index c6fe857..9d7fcf4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "l-s" -version = "0.5.0" +version = "0.5.1" authors = ["licsber "] edition = "2021" diff --git a/README.md b/README.md index a102a3e..e37f71d 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ - `size`: 文件大小(字节) - `friendly_size`: 人类可读的文件大小 - `mtime`: 文件修改时间(Unix 时间戳) -- `head_115`: 115网盘头部哈希(前128KB的SHA1) -- `head_baidu`: 百度网盘头部哈希(前256KB的MD5) +- `head_115`: 115网盘头部哈希(固定 128KB 缓冲区的 SHA1;文件不足 128KB 时尾部按 0 填充后计算) +- `head_baidu`: 百度网盘头部哈希(固定 256KB 缓冲区的 MD5;文件不足 256KB 时尾部按 0 填充后计算) - `ed2k`: ED2K 哈希 - `md5`: MD5 哈希 - `sha1`: SHA1 哈希 @@ -90,7 +90,9 @@ | **群晖等 NAS** | `@Recently-Snapshot`(快照)、`@Recycle`(回收站)、`.@__thumb`(缩略图缓存)、`@Transcode`(转码) | — | — | | **Windows** | `$RECYCLE.BIN` | `Thumbs.db`、`desktop.ini` | — | | **macOS** | — | `.DS_Store` | 以 `._` 开头(AppleDouble 资源叉) | -| **本工具** | `meta`(元数据子目录) | `meta.json`、`meta-old.json`、`licsber-bak.json`(兼容旧工具) | 以 `Thumb_` 开头的缩略图文件 | +| **本工具** | `meta`(元数据子目录) | `meta.json`、`meta-old.json` | 以 `.l-s-tmp-` 开头的临时写入文件 | +| **兼容旧工具** | — | `licsber-bak.json` | — | +| **缩略图** | — | — | 以 `Thumb_` 开头的缩略图文件 | **子目录递归优化** diff --git a/src/main.rs b/src/main.rs index 4f6909f..0c1186a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,10 +4,10 @@ mod head_hash; mod meta; mod utils; -use std::fs::{self, File}; +use std::fs::{self, File, OpenOptions}; use std::io::Write; use std::path::{Path, PathBuf}; -use std::time::Instant; +use std::time::{Instant, SystemTime, UNIX_EPOCH}; use anyhow::{Context, Result}; use clap::Parser; @@ -57,7 +57,7 @@ fn process_file(path: &Path) -> Result<()> { tracker.finish("处理完成"); let json = meta.to_pretty_json()?; println!("{}", json); - fs::write(&save_path, json)?; + write_atomic(&save_path, &json)?; return Ok(()); } @@ -98,9 +98,7 @@ fn process_dir(path: &Path) -> Result<()> { if !meta_path.exists() { let snapshot = DirSnapshot::build_root(path)?; let json = serde_json::to_string_pretty(&snapshot)?; - let mut file = File::create(&meta_path) - .with_context(|| format!("无法写入: {}", meta_path.display()))?; - file.write_all(json.as_bytes())?; + write_atomic(&meta_path, &json)?; return Ok(()); } @@ -151,3 +149,43 @@ fn process_dir(path: &Path) -> Result<()> { Ok(()) } + +fn write_atomic(path: &Path, contents: &str) -> Result<()> { + let parent = path + .parent() + .map(Path::to_path_buf) + .unwrap_or_else(|| PathBuf::from(".")); + let nanos = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_nanos()) + .unwrap_or(0); + let tmp_path = parent.join(format!(".l-s-tmp-{}-{nanos}", std::process::id())); + + let result = (|| -> Result<()> { + let mut file = OpenOptions::new() + .write(true) + .create_new(true) + .open(&tmp_path) + .with_context(|| format!("无法创建临时文件: {}", tmp_path.display()))?; + file.write_all(contents.as_bytes()) + .with_context(|| format!("无法写入临时文件: {}", tmp_path.display()))?; + file.sync_all() + .with_context(|| format!("无法同步临时文件: {}", tmp_path.display()))?; + drop(file); + + fs::rename(&tmp_path, path).with_context(|| { + format!( + "无法将临时文件重命名为目标文件: {} -> {}", + tmp_path.display(), + path.display() + ) + })?; + Ok(()) + })(); + + if result.is_err() { + let _ = fs::remove_file(&tmp_path); + } + + result +} diff --git a/src/meta/file.rs b/src/meta/file.rs index 63f278f..2ca19ed 100644 --- a/src/meta/file.rs +++ b/src/meta/file.rs @@ -32,7 +32,11 @@ pub struct FileMeta { } impl FileMeta { - pub fn from_path_with_callback(path: &Path, mut on_bytes_read: F1, mut on_iop: F2) -> Result + pub fn from_path_with_callback( + path: &Path, + mut on_bytes_read: F1, + mut on_iop: F2, + ) -> Result where F1: FnMut(u64), F2: FnMut(), @@ -120,7 +124,11 @@ impl FileMeta { } } -pub fn calc_xxh128_with_callback(path: &Path, mut on_bytes_read: F1, mut on_iop: F2) -> Result +pub fn calc_xxh128_with_callback( + path: &Path, + mut on_bytes_read: F1, + mut on_iop: F2, +) -> Result where F1: FnMut(u64), F2: FnMut(), diff --git a/src/meta/progress.rs b/src/meta/progress.rs index bdc5bb0..80c73f2 100644 --- a/src/meta/progress.rs +++ b/src/meta/progress.rs @@ -9,11 +9,11 @@ use crate::utils::friendly_size; /// 进度跟踪器,封装进度条和 IO 统计信息 pub struct ProgressTracker { multi: Option, - file_progress_bar: Option, // 文件数量进度条 - current_file_bar: Option, // 当前文件进度条 + file_progress_bar: Option, // 文件数量进度条 + current_file_bar: Option, // 当前文件进度条 bytes_read: Arc, - current_file_bytes: Arc, // 当前文件已读字节数 - current_file_size: Arc, // 当前文件总大小 + current_file_bytes: Arc, // 当前文件已读字节数 + current_file_size: Arc, // 当前文件总大小 iops: Arc, start_time: Instant, last_update: Arc, @@ -44,7 +44,7 @@ impl ProgressTracker { .unwrap() .progress_chars("=>-"), ); - current_pb.set_length(0); // 设置为0长度来隐藏 + current_pb.set_length(0); // 设置为0长度来隐藏 (Some(multi), Some(file_pb), Some(current_pb)) } else { @@ -163,7 +163,10 @@ impl ProgressTracker { String::new() }; - pb.set_message(format!("IO速度: {}/s | IOPS: {:.0} | {}", speed_str, iops, eta_str)); + pb.set_message(format!( + "IO速度: {}/s | IOPS: {:.0} | {}", + speed_str, iops, eta_str + )); } } } @@ -246,7 +249,10 @@ impl ProgressTracker { String::new() }; - pb.set_message(format!("IO速度: {}/s | IOPS: {:.0} | {}", speed_str, iops_value, eta_str)); + pb.set_message(format!( + "IO速度: {}/s | IOPS: {:.0} | {}", + speed_str, iops_value, eta_str + )); } } diff --git a/src/meta/tree.rs b/src/meta/tree.rs index 2bb6d9e..a9afb68 100644 --- a/src/meta/tree.rs +++ b/src/meta/tree.rs @@ -83,9 +83,7 @@ impl DirSnapshot { } // 获取文件大小并开始跟踪 - let file_size = entry.metadata() - .map(|m| m.len()) - .unwrap_or(0); + let file_size = entry.metadata().map(|m| m.len()).unwrap_or(0); tracker.start_file(file_size, &name); let on_bytes = tracker.bytes_callback(); @@ -124,9 +122,9 @@ impl DirSnapshot { /// 校验通过则返回已有的 DirSnapshot,否则返回 Err 终止流程。 fn verify_and_load(path: &Path, tracker: &ProgressTracker) -> Result { let meta_path = path.join("meta.json"); - let meta_file = File::open(&meta_path) - .with_context(|| format!("无法读取: {}", meta_path.display()))?; - let snapshot: Self = serde_json::from_reader(meta_file) + let meta_file = + File::open(&meta_path).with_context(|| format!("无法读取: {}", meta_path.display()))?; + let mut snapshot: Self = serde_json::from_reader(meta_file) .with_context(|| format!("无法解析: {}", meta_path.display()))?; let mut stored = snapshot.collect_file_map(path); @@ -162,6 +160,11 @@ impl DirSnapshot { } else { eprintln!("{msg}"); } + snapshot.dir_name = path + .file_name() + .map(basename) + .unwrap_or_else(|| path.to_string_lossy().to_string()); + snapshot.v = None; Ok(snapshot) } } @@ -252,9 +255,7 @@ fn walk_dir_with_progress( } // 获取文件大小并开始跟踪 - let file_size = entry.metadata() - .map(|m| m.len()) - .unwrap_or(0); + let file_size = entry.metadata().map(|m| m.len()).unwrap_or(0); tracker.start_file(file_size, &name); let on_bytes = tracker.bytes_callback(); diff --git a/src/utils.rs b/src/utils.rs index 3684036..add2e61 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -44,6 +44,7 @@ pub fn should_skip_file(name: &str) -> bool { .any(|item| item.eq_ignore_ascii_case(name)) || name.starts_with("._") || name.starts_with("Thumb_") + || name.starts_with(".l-s-tmp-") } pub fn hex_upper(bytes: impl AsRef<[u8]>) -> String { @@ -56,7 +57,7 @@ pub fn hex_upper(bytes: impl AsRef<[u8]>) -> String { #[cfg(test)] mod tests { - use super::friendly_size; + use super::{friendly_size, should_skip_file}; #[test] fn friendly_size_formats_units() { @@ -65,4 +66,9 @@ mod tests { assert_eq!(friendly_size(1024), "1.00KB"); assert_eq!(friendly_size(1024 * 1024), "1.00MB"); } + + #[test] + fn should_skip_atomic_write_temp_files() { + assert!(should_skip_file(".l-s-tmp-123-456")); + } }