feat: [#1932] l-s v0.5.1 原子写入保护及文档更新

This commit is contained in:
2026-05-08 00:18:30 +08:00
parent e821dcab14
commit 30186c23fb
8 changed files with 193 additions and 95 deletions
Generated
+103 -66
View File
@@ -4,9 +4,9 @@ version = 4
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.21" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
@@ -19,15 +19,15 @@ dependencies = [
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.13" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]] [[package]]
name = "anstyle-parse" name = "anstyle-parse"
version = "0.2.7" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [ dependencies = [
"utf8parse", "utf8parse",
] ]
@@ -54,9 +54,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.100" version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@@ -69,9 +69,9 @@ dependencies = [
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.19.1" version = "3.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -81,9 +81,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.53" version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@@ -91,9 +91,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.53" version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@@ -103,9 +103,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.5.49" version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@@ -115,25 +115,24 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.7.6" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]] [[package]]
name = "console" name = "console"
version = "0.16.2" version = "0.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87"
dependencies = [ dependencies = [
"encode_unicode", "encode_unicode",
"libc", "libc",
"once_cell",
"unicode-width", "unicode-width",
"windows-sys", "windows-sys",
] ]
@@ -183,6 +182,30 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" 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]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.7" version = "0.14.7"
@@ -201,9 +224,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "indicatif" name = "indicatif"
version = "0.18.3" version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb"
dependencies = [ dependencies = [
"console", "console",
"portable-atomic", "portable-atomic",
@@ -220,23 +243,25 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.16" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.83" version = "0.3.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
dependencies = [ dependencies = [
"cfg-if",
"futures-util",
"once_cell", "once_cell",
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]] [[package]]
name = "l-s" name = "l-s"
version = "0.5.0" version = "0.5.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@@ -252,9 +277,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.178" version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]] [[package]]
name = "md-5" name = "md-5"
@@ -277,15 +302,15 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.6" version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.21.3" version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]] [[package]]
name = "once_cell_polyfill" name = "once_cell_polyfill"
@@ -294,25 +319,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]] [[package]]
name = "portable-atomic" name = "pin-project-lite"
version = "1.12.0" version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.103" version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.42" version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -323,12 +354,6 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "ryu"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"
@@ -361,15 +386,15 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.145" version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
"ryu",
"serde", "serde",
"serde_core", "serde_core",
"zmij",
] ]
[[package]] [[package]]
@@ -394,6 +419,12 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@@ -402,9 +433,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.111" version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -413,15 +444,15 @@ dependencies = [
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.19.0" version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.22" version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
@@ -449,9 +480,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.106" version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@@ -462,9 +493,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.106" version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -472,9 +503,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.106" version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
@@ -485,9 +516,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.106" version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -522,3 +553,9 @@ name = "xxhash-rust"
version = "0.8.15" version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "l-s" name = "l-s"
version = "0.5.0" version = "0.5.1"
authors = ["licsber <admin@licsber.site>"] authors = ["licsber <admin@licsber.site>"]
edition = "2021" edition = "2021"
+5 -3
View File
@@ -62,8 +62,8 @@
- `size`: 文件大小(字节) - `size`: 文件大小(字节)
- `friendly_size`: 人类可读的文件大小 - `friendly_size`: 人类可读的文件大小
- `mtime`: 文件修改时间(Unix 时间戳) - `mtime`: 文件修改时间(Unix 时间戳)
- `head_115`: 115网盘头部哈希(128KB的SHA1 - `head_115`: 115网盘头部哈希(固定 128KB 缓冲区的 SHA1;文件不足 128KB 时尾部按 0 填充后计算
- `head_baidu`: 百度网盘头部哈希(256KB的MD5 - `head_baidu`: 百度网盘头部哈希(固定 256KB 缓冲区的 MD5;文件不足 256KB 时尾部按 0 填充后计算
- `ed2k`: ED2K 哈希 - `ed2k`: ED2K 哈希
- `md5`: MD5 哈希 - `md5`: MD5 哈希
- `sha1`: SHA1 哈希 - `sha1`: SHA1 哈希
@@ -90,7 +90,9 @@
| **群晖等 NAS** | `@Recently-Snapshot`(快照)、`@Recycle`(回收站)、`.@__thumb`(缩略图缓存)、`@Transcode`(转码) | — | — | | **群晖等 NAS** | `@Recently-Snapshot`(快照)、`@Recycle`(回收站)、`.@__thumb`(缩略图缓存)、`@Transcode`(转码) | — | — |
| **Windows** | `$RECYCLE.BIN` | `Thumbs.db``desktop.ini` | — | | **Windows** | `$RECYCLE.BIN` | `Thumbs.db``desktop.ini` | — |
| **macOS** | — | `.DS_Store` | 以 `._` 开头(AppleDouble 资源叉) | | **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_` 开头的缩略图文件 |
**子目录递归优化** **子目录递归优化**
+44 -6
View File
@@ -4,10 +4,10 @@ mod head_hash;
mod meta; mod meta;
mod utils; mod utils;
use std::fs::{self, File}; use std::fs::{self, File, OpenOptions};
use std::io::Write; use std::io::Write;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Instant; use std::time::{Instant, SystemTime, UNIX_EPOCH};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::Parser; use clap::Parser;
@@ -57,7 +57,7 @@ fn process_file(path: &Path) -> Result<()> {
tracker.finish("处理完成"); tracker.finish("处理完成");
let json = meta.to_pretty_json()?; let json = meta.to_pretty_json()?;
println!("{}", json); println!("{}", json);
fs::write(&save_path, json)?; write_atomic(&save_path, &json)?;
return Ok(()); return Ok(());
} }
@@ -98,9 +98,7 @@ fn process_dir(path: &Path) -> Result<()> {
if !meta_path.exists() { if !meta_path.exists() {
let snapshot = DirSnapshot::build_root(path)?; let snapshot = DirSnapshot::build_root(path)?;
let json = serde_json::to_string_pretty(&snapshot)?; let json = serde_json::to_string_pretty(&snapshot)?;
let mut file = File::create(&meta_path) write_atomic(&meta_path, &json)?;
.with_context(|| format!("无法写入: {}", meta_path.display()))?;
file.write_all(json.as_bytes())?;
return Ok(()); return Ok(());
} }
@@ -151,3 +149,43 @@ fn process_dir(path: &Path) -> Result<()> {
Ok(()) 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
}
+10 -2
View File
@@ -32,7 +32,11 @@ pub struct FileMeta {
} }
impl FileMeta { impl FileMeta {
pub fn from_path_with_callback<F1, F2>(path: &Path, mut on_bytes_read: F1, mut on_iop: F2) -> Result<Self> pub fn from_path_with_callback<F1, F2>(
path: &Path,
mut on_bytes_read: F1,
mut on_iop: F2,
) -> Result<Self>
where where
F1: FnMut(u64), F1: FnMut(u64),
F2: FnMut(), F2: FnMut(),
@@ -120,7 +124,11 @@ impl FileMeta {
} }
} }
pub fn calc_xxh128_with_callback<F1, F2>(path: &Path, mut on_bytes_read: F1, mut on_iop: F2) -> Result<String> pub fn calc_xxh128_with_callback<F1, F2>(
path: &Path,
mut on_bytes_read: F1,
mut on_iop: F2,
) -> Result<String>
where where
F1: FnMut(u64), F1: FnMut(u64),
F2: FnMut(), F2: FnMut(),
+8 -2
View File
@@ -163,7 +163,10 @@ impl ProgressTracker {
String::new() 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() 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
));
} }
} }
+10 -9
View File
@@ -83,9 +83,7 @@ impl DirSnapshot {
} }
// 获取文件大小并开始跟踪 // 获取文件大小并开始跟踪
let file_size = entry.metadata() let file_size = entry.metadata().map(|m| m.len()).unwrap_or(0);
.map(|m| m.len())
.unwrap_or(0);
tracker.start_file(file_size, &name); tracker.start_file(file_size, &name);
let on_bytes = tracker.bytes_callback(); let on_bytes = tracker.bytes_callback();
@@ -124,9 +122,9 @@ impl DirSnapshot {
/// 校验通过则返回已有的 DirSnapshot,否则返回 Err 终止流程。 /// 校验通过则返回已有的 DirSnapshot,否则返回 Err 终止流程。
fn verify_and_load(path: &Path, tracker: &ProgressTracker) -> Result<Self> { fn verify_and_load(path: &Path, tracker: &ProgressTracker) -> Result<Self> {
let meta_path = path.join("meta.json"); let meta_path = path.join("meta.json");
let meta_file = File::open(&meta_path) let meta_file =
.with_context(|| format!("无法读取: {}", meta_path.display()))?; File::open(&meta_path).with_context(|| format!("无法读取: {}", meta_path.display()))?;
let snapshot: Self = serde_json::from_reader(meta_file) let mut snapshot: Self = serde_json::from_reader(meta_file)
.with_context(|| format!("无法解析: {}", meta_path.display()))?; .with_context(|| format!("无法解析: {}", meta_path.display()))?;
let mut stored = snapshot.collect_file_map(path); let mut stored = snapshot.collect_file_map(path);
@@ -162,6 +160,11 @@ impl DirSnapshot {
} else { } else {
eprintln!("{msg}"); eprintln!("{msg}");
} }
snapshot.dir_name = path
.file_name()
.map(basename)
.unwrap_or_else(|| path.to_string_lossy().to_string());
snapshot.v = None;
Ok(snapshot) Ok(snapshot)
} }
} }
@@ -252,9 +255,7 @@ fn walk_dir_with_progress(
} }
// 获取文件大小并开始跟踪 // 获取文件大小并开始跟踪
let file_size = entry.metadata() let file_size = entry.metadata().map(|m| m.len()).unwrap_or(0);
.map(|m| m.len())
.unwrap_or(0);
tracker.start_file(file_size, &name); tracker.start_file(file_size, &name);
let on_bytes = tracker.bytes_callback(); let on_bytes = tracker.bytes_callback();
+7 -1
View File
@@ -44,6 +44,7 @@ pub fn should_skip_file(name: &str) -> bool {
.any(|item| item.eq_ignore_ascii_case(name)) .any(|item| item.eq_ignore_ascii_case(name))
|| name.starts_with("._") || name.starts_with("._")
|| name.starts_with("Thumb_") || name.starts_with("Thumb_")
|| name.starts_with(".l-s-tmp-")
} }
pub fn hex_upper(bytes: impl AsRef<[u8]>) -> String { pub fn hex_upper(bytes: impl AsRef<[u8]>) -> String {
@@ -56,7 +57,7 @@ pub fn hex_upper(bytes: impl AsRef<[u8]>) -> String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::friendly_size; use super::{friendly_size, should_skip_file};
#[test] #[test]
fn friendly_size_formats_units() { fn friendly_size_formats_units() {
@@ -65,4 +66,9 @@ mod tests {
assert_eq!(friendly_size(1024), "1.00KB"); assert_eq!(friendly_size(1024), "1.00KB");
assert_eq!(friendly_size(1024 * 1024), "1.00MB"); 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"));
}
} }