Compare commits
1 Commits
master
...
deprecated
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a94fdd4a9 |
279
Cargo.lock
generated
279
Cargo.lock
generated
@@ -4,18 +4,18 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.18"
|
version = "0.7.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
@@ -26,6 +26,15 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bsvfs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"camino",
|
||||||
|
"tempfile",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "camino"
|
name = "camino"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -54,6 +63,12 @@ dependencies = [
|
|||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -62,9 +77,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.1.5"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef"
|
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -79,30 +94,69 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "errno"
|
||||||
version = "0.14.4"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "instant"
|
||||||
version = "0.2.3"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3"
|
||||||
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libbsv"
|
name = "libbsv"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bsvfs",
|
||||||
"camino",
|
"camino",
|
||||||
"cas-core",
|
"cas-core",
|
||||||
"cas-simple",
|
"cas-simple",
|
||||||
@@ -112,9 +166,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.98"
|
version = "0.2.140"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
@@ -128,12 +188,6 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.27"
|
version = "1.0.27"
|
||||||
@@ -152,60 +206,20 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
"rand_hc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_hc"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.9"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
|
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.6.0"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -214,30 +228,35 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.27"
|
version = "0.6.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "rustix"
|
||||||
version = "0.5.3"
|
version = "0.36.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.127"
|
version = "1.0.155"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
|
checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.9.5"
|
version = "0.9.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
|
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -259,16 +278,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.2.0"
|
version = "3.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"fastrand",
|
||||||
"rand",
|
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"rustix",
|
||||||
"winapi",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -293,18 +311,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.5.8"
|
version = "0.5.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.13.0"
|
version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
@@ -314,15 +332,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.3"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.10.2+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
@@ -345,3 +357,84 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
|
"bsvfs",
|
||||||
"cas-core",
|
"cas-core",
|
||||||
"cas-simple",
|
"cas-simple",
|
||||||
"libbsv",
|
"libbsv",
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cas-core"
|
name = "bsvfs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Simon Boyé <sim.boye@gmail.com>"]
|
authors = ["Simon Boyé <sim.boye@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "1.0.25"
|
|
||||||
camino = { version = "1.0.7" }
|
camino = { version = "1.0.7" }
|
||||||
|
thiserror = "1.0.25"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
tempfile = "3.2.0"
|
||||||
|
|||||||
491
bsvfs/src/fs.rs
Normal file
491
bsvfs/src/fs.rs
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
// This file is part of bsv.
|
||||||
|
//
|
||||||
|
// bsv is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU Affero General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// bsv is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the Affero GNU General Public License
|
||||||
|
// along with bsv. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
io::{Read, Result, Seek, Write},
|
||||||
|
time::SystemTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
use camino::{Utf8Path, Utf8PathBuf};
|
||||||
|
|
||||||
|
|
||||||
|
// FileType
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum FileType {
|
||||||
|
Dir,
|
||||||
|
File,
|
||||||
|
Symlink,
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileType {
|
||||||
|
pub fn is_dir(&self) -> bool {
|
||||||
|
*self == FileType::Dir
|
||||||
|
}
|
||||||
|
pub fn is_file(&self) -> bool {
|
||||||
|
*self == FileType::File
|
||||||
|
}
|
||||||
|
pub fn is_symlink(&self) -> bool {
|
||||||
|
*self == FileType::Symlink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Permissions
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct Permissions {
|
||||||
|
read: bool,
|
||||||
|
write: bool,
|
||||||
|
execute: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Permissions {
|
||||||
|
pub fn new(read: bool, write: bool, execute: bool) -> Self {
|
||||||
|
Permissions { read, write, execute }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_read(&self) -> bool {
|
||||||
|
self.read
|
||||||
|
}
|
||||||
|
pub fn is_write(&self) -> bool {
|
||||||
|
self.write
|
||||||
|
}
|
||||||
|
pub fn is_execute(&self) -> bool {
|
||||||
|
self.execute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Permissions {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
f.write_char(if self.read { 'r' } else { '-' })?;
|
||||||
|
f.write_char(if self.write { 'w' } else { '-' })?;
|
||||||
|
f.write_char(if self.execute { 'x' } else { '-' })?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for Permissions {
|
||||||
|
type Err = ParsePermissionError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
|
if s.len() == 3 {
|
||||||
|
let mut chars = s.chars();
|
||||||
|
let read = parse_permission_char(&mut chars, 'r')?;
|
||||||
|
let write = parse_permission_char(&mut chars, 'w')?;
|
||||||
|
let execute = parse_permission_char(&mut chars, 'x')?;
|
||||||
|
assert!(chars.next().is_none());
|
||||||
|
|
||||||
|
Ok(Self { read, write, execute })
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(ParsePermissionError::InvalidLength(s.len()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_permission_char(chars: &mut std::str::Chars, bit_char: char)
|
||||||
|
-> std::result::Result<bool, ParsePermissionError>
|
||||||
|
{
|
||||||
|
let c = chars.next().unwrap();
|
||||||
|
if c == bit_char || c == '-' {
|
||||||
|
Ok(c == bit_char)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(ParsePermissionError::InvalidChar(bit_char, c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ParsePermissionError {
|
||||||
|
InvalidLength(usize),
|
||||||
|
InvalidChar(char, char),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ParsePermissionError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::InvalidLength(length) => write!(f, "expected 3 characters, got {}", length),
|
||||||
|
Self::InvalidChar(expected, actual) => write!(f, "exected character {}, got {}", expected, actual),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ParsePermissionError {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
|
||||||
|
pub trait Metadata {
|
||||||
|
fn file_type(&self) -> FileType;
|
||||||
|
fn is_dir(&self) -> bool {
|
||||||
|
self.file_type().is_dir()
|
||||||
|
}
|
||||||
|
fn is_file(&self) -> bool {
|
||||||
|
self.file_type().is_file()
|
||||||
|
}
|
||||||
|
fn is_symlink(&self) -> bool {
|
||||||
|
self.file_type().is_symlink()
|
||||||
|
}
|
||||||
|
fn len(&self) -> u64;
|
||||||
|
fn permissions(&self) -> Permissions;
|
||||||
|
fn modified(&self) -> Result<SystemTime>;
|
||||||
|
fn created(&self) -> Result<SystemTime>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// File
|
||||||
|
|
||||||
|
const OPEN_READ: u8 = 0x01;
|
||||||
|
const OPEN_WRITE: u8 = 0x02;
|
||||||
|
const OPEN_APPEND: u8 = 0x04;
|
||||||
|
const OPEN_TRUNCATE: u8 = 0x08;
|
||||||
|
const OPEN_CREATE: u8 = 0x10;
|
||||||
|
const OPEN_CREATE_NEW: u8 = 0x20;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct OpenOptions {
|
||||||
|
options: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpenOptions {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
OpenOptions {
|
||||||
|
options: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_read(&self) -> bool {
|
||||||
|
(self.options & OPEN_READ) != 0
|
||||||
|
}
|
||||||
|
pub fn is_write(&self) -> bool {
|
||||||
|
(self.options & OPEN_WRITE) != 0
|
||||||
|
}
|
||||||
|
pub fn is_append(&self) -> bool {
|
||||||
|
(self.options & OPEN_APPEND) != 0
|
||||||
|
}
|
||||||
|
pub fn is_truncate(&self) -> bool {
|
||||||
|
(self.options & OPEN_TRUNCATE) != 0
|
||||||
|
}
|
||||||
|
pub fn is_create(&self) -> bool {
|
||||||
|
(self.options & OPEN_CREATE) != 0
|
||||||
|
}
|
||||||
|
pub fn is_create_new(&self) -> bool {
|
||||||
|
(self.options & OPEN_CREATE_NEW) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self, read: bool) -> &mut Self {
|
||||||
|
if read {
|
||||||
|
self.options |= OPEN_READ;
|
||||||
|
} else {
|
||||||
|
self.options &= !OPEN_READ;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, write: bool) -> &mut Self {
|
||||||
|
if write {
|
||||||
|
self.options |= OPEN_WRITE;
|
||||||
|
} else {
|
||||||
|
self.options &= !OPEN_WRITE;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, append: bool) -> &mut Self {
|
||||||
|
if append {
|
||||||
|
self.options |= OPEN_APPEND;
|
||||||
|
} else {
|
||||||
|
self.options &= !OPEN_APPEND;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn truncate(&mut self, truncate: bool) -> &mut Self {
|
||||||
|
if truncate {
|
||||||
|
self.options |= OPEN_TRUNCATE;
|
||||||
|
} else {
|
||||||
|
self.options &= !OPEN_TRUNCATE;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(&mut self, create: bool) -> &mut Self {
|
||||||
|
if create {
|
||||||
|
self.options |= OPEN_CREATE;
|
||||||
|
} else {
|
||||||
|
self.options &= !OPEN_CREATE;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_new(&mut self, create_new: bool) -> &mut Self {
|
||||||
|
if create_new {
|
||||||
|
self.options |= OPEN_CREATE_NEW;
|
||||||
|
} else {
|
||||||
|
self.options &= !OPEN_CREATE_NEW;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait File: Sized + Read + Write + Seek {
|
||||||
|
type Metadata: Metadata;
|
||||||
|
|
||||||
|
fn metadata(&self) -> Result<Self::Metadata>;
|
||||||
|
|
||||||
|
fn set_len(&self, size: u64) -> Result<()>;
|
||||||
|
|
||||||
|
fn sync_data(&self) -> Result<()>;
|
||||||
|
fn sync_all(&self) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DirEntry
|
||||||
|
|
||||||
|
pub trait DirEntry {
|
||||||
|
type Metadata: Metadata;
|
||||||
|
|
||||||
|
fn path(&self) -> Result<Utf8PathBuf>;
|
||||||
|
fn metadata(&self) -> Result<Self::Metadata>;
|
||||||
|
fn file_type(&self) -> Result<FileType> {
|
||||||
|
Ok(self.metadata()?.file_type())
|
||||||
|
}
|
||||||
|
fn file_name(&self) -> Result<String> {
|
||||||
|
Ok(
|
||||||
|
self.path()?
|
||||||
|
.file_name()
|
||||||
|
.expect("DirEntry::path() returned an invalid path with no file name")
|
||||||
|
.to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FileSystem
|
||||||
|
|
||||||
|
pub trait FileSystem {
|
||||||
|
type File: File;
|
||||||
|
type DirEntry: DirEntry;
|
||||||
|
type ReadDir: Iterator<Item=Result<Self::DirEntry>>;
|
||||||
|
|
||||||
|
fn open_with_options<P: AsRef<Utf8Path>>(&self, path: P, options: &OpenOptions) -> Result<Self::File>;
|
||||||
|
|
||||||
|
fn open<P: AsRef<Utf8Path>>(&self, path: P) -> Result<Self::File> {
|
||||||
|
self.open_with_options(
|
||||||
|
path,
|
||||||
|
OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn create_or_truncate<P: AsRef<Utf8Path>>(&self, path: P) -> Result<Self::File> {
|
||||||
|
self.open_with_options(
|
||||||
|
path,
|
||||||
|
OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn create_new<P: AsRef<Utf8Path>>(&self, path: P) -> Result<Self::File> {
|
||||||
|
self.open_with_options(
|
||||||
|
path,
|
||||||
|
OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create_new(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_dir<P: AsRef<Utf8Path>>(&self, path: P) -> Result<Self::ReadDir>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file_type() {
|
||||||
|
let dir = FileType::Dir;
|
||||||
|
assert!(dir.is_dir());
|
||||||
|
assert!(!dir.is_file());
|
||||||
|
assert!(!dir.is_symlink());
|
||||||
|
|
||||||
|
let file = FileType::File;
|
||||||
|
assert!(!file.is_dir());
|
||||||
|
assert!(file.is_file());
|
||||||
|
assert!(!file.is_symlink());
|
||||||
|
|
||||||
|
let symlink = FileType::Symlink;
|
||||||
|
assert!(!symlink.is_dir());
|
||||||
|
assert!(!symlink.is_file());
|
||||||
|
assert!(symlink.is_symlink());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_open_options() {
|
||||||
|
let mut options = OpenOptions::new();
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.read(true);
|
||||||
|
assert!(options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.read(false);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.write(true);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.write(false);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.append(true);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.append(false);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.truncate(true);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.truncate(false);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.create(true);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.create(false);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
|
||||||
|
options.create_new(true);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(options.is_create_new());
|
||||||
|
|
||||||
|
options.create_new(false);
|
||||||
|
assert!(!options.is_read());
|
||||||
|
assert!(!options.is_write());
|
||||||
|
assert!(!options.is_append());
|
||||||
|
assert!(!options.is_truncate());
|
||||||
|
assert!(!options.is_create());
|
||||||
|
assert!(!options.is_create_new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_permission_display() {
|
||||||
|
let expected = [
|
||||||
|
"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx",
|
||||||
|
];
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
let read = (i & 0x04) != 0;
|
||||||
|
let write = (i & 0x02) != 0;
|
||||||
|
let execute = (i & 0x01) != 0;
|
||||||
|
|
||||||
|
let perm = Permissions { read, write, execute };
|
||||||
|
let perm_str = perm.to_string();
|
||||||
|
|
||||||
|
assert_eq!(perm_str, expected[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_permission_from_str() {
|
||||||
|
let perms = [
|
||||||
|
"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx",
|
||||||
|
];
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
let read = (i & 0x04) != 0;
|
||||||
|
let write = (i & 0x02) != 0;
|
||||||
|
let execute = (i & 0x01) != 0;
|
||||||
|
|
||||||
|
let perm = Permissions::from_str(perms[i]).unwrap();
|
||||||
|
let expected = Permissions { read, write, execute };
|
||||||
|
|
||||||
|
assert_eq!(perm, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(Permissions::from_str("rw"), Err(ParsePermissionError::InvalidLength(2)));
|
||||||
|
assert_eq!(Permissions::from_str("rw--"), Err(ParsePermissionError::InvalidLength(4)));
|
||||||
|
assert_eq!(Permissions::from_str("-x-"), Err(ParsePermissionError::InvalidChar('w', 'x')));
|
||||||
|
assert_eq!(Permissions::from_str("123"), Err(ParsePermissionError::InvalidChar('r', '1')));
|
||||||
|
}
|
||||||
|
}
|
||||||
386
bsvfs/src/fs_impl.rs
Normal file
386
bsvfs/src/fs_impl.rs
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
// This file is part of bsv.
|
||||||
|
//
|
||||||
|
// bsv is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU Affero General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// bsv is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the Affero GNU General Public License
|
||||||
|
// along with bsv. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
ffi::OsString,
|
||||||
|
fmt::{Arguments, Display},
|
||||||
|
fs::{
|
||||||
|
self,
|
||||||
|
DirEntry as StdDirEntry,
|
||||||
|
File as StdFile,
|
||||||
|
Metadata as StdMetadata,
|
||||||
|
ReadDir as StdReadDir,
|
||||||
|
},
|
||||||
|
io::{self, IoSlice, IoSliceMut, Read, Result, Seek, SeekFrom, Write},
|
||||||
|
time::SystemTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
use camino::{Utf8Path, Utf8PathBuf};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
fs::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct NonUtf8Filename {
|
||||||
|
filename: OsString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NonUtf8Filename {
|
||||||
|
fn new(filename: OsString) -> Self {
|
||||||
|
Self {
|
||||||
|
filename: filename,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for NonUtf8Filename {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Non UTF-8 filename: '{:?}'", self.filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for NonUtf8Filename {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn as_io_error<E>(error: E) -> io::Error
|
||||||
|
where E: Into<Box<dyn Error + Send + Sync>>,
|
||||||
|
{
|
||||||
|
io::Error::new(io::ErrorKind::Other, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_string(os_string: OsString) -> Result<String> {
|
||||||
|
os_string.into_string()
|
||||||
|
.map_err(|filename| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
NonUtf8Filename::new(filename),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn as_filetype(std_filetype: fs::FileType) -> FileType {
|
||||||
|
if std_filetype.is_dir() {
|
||||||
|
FileType::Dir
|
||||||
|
} else if std_filetype.is_file() {
|
||||||
|
FileType::File
|
||||||
|
} else if std_filetype.is_symlink() {
|
||||||
|
FileType::Symlink
|
||||||
|
} else {
|
||||||
|
FileType::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SysMetadata {
|
||||||
|
metadata: StdMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metadata for SysMetadata {
|
||||||
|
fn file_type(&self) -> FileType {
|
||||||
|
as_filetype(self.metadata.file_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> u64 {
|
||||||
|
self.metadata.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
fn permissions(&self) -> Permissions {
|
||||||
|
Permissions(true, self.metadata.permissions().readonly(), false)
|
||||||
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn permissions(&self) -> Permissions {
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
let mode = self.metadata.mode();
|
||||||
|
Permissions::new(
|
||||||
|
mode & 0o100 != 0,
|
||||||
|
mode & 0o200 != 0,
|
||||||
|
mode & 0o400 != 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modified(&self) -> Result<SystemTime> {
|
||||||
|
Ok(self.metadata.modified()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn created(&self) -> Result<SystemTime> {
|
||||||
|
Ok(self.metadata.created()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StdMetadata> for SysMetadata {
|
||||||
|
fn from(value: StdMetadata) -> Self {
|
||||||
|
SysMetadata {
|
||||||
|
metadata: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SysFile {
|
||||||
|
file: StdFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl File for SysFile {
|
||||||
|
type Metadata = SysMetadata;
|
||||||
|
|
||||||
|
fn metadata(&self) -> Result<Self::Metadata> {
|
||||||
|
Ok(self.file.metadata()?.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_len(&self, size: u64) -> Result<()> {
|
||||||
|
Ok(self.file.set_len(size)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_data(&self) -> Result<()> {
|
||||||
|
Ok(self.file.sync_data()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_all(&self) -> Result<()> {
|
||||||
|
Ok(self.file.sync_all()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for SysFile {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.file.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
|
||||||
|
self.file.read_vectored(bufs)
|
||||||
|
}
|
||||||
|
// fn is_read_vectored(&self) -> bool {
|
||||||
|
// self.file.is_read_vectored()
|
||||||
|
// }
|
||||||
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||||
|
self.file.read_to_end(buf)
|
||||||
|
}
|
||||||
|
fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
|
||||||
|
self.file.read_to_string(buf)
|
||||||
|
}
|
||||||
|
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
|
||||||
|
self.file.read_exact(buf)
|
||||||
|
}
|
||||||
|
// fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
|
||||||
|
// self.file.read_buf(buf)
|
||||||
|
// }
|
||||||
|
// fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> {
|
||||||
|
// self.file.read_buf_exact(cursor)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Seek for SysFile {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
|
||||||
|
self.file.seek(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rewind(&mut self) -> Result<()> {
|
||||||
|
self.file.rewind()
|
||||||
|
}
|
||||||
|
// fn stream_len(&mut self) -> Result<u64> {
|
||||||
|
// self.file.stream_len()
|
||||||
|
// }
|
||||||
|
fn stream_position(&mut self) -> Result<u64> {
|
||||||
|
self.file.stream_position()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for SysFile {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
self.file.write(buf)
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> Result<()> {
|
||||||
|
self.file.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
|
||||||
|
self.file.write_vectored(bufs)
|
||||||
|
}
|
||||||
|
// fn is_write_vectored(&self) -> bool {
|
||||||
|
// self.file.is_write_vectored()
|
||||||
|
// }
|
||||||
|
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||||
|
self.file.write_all(buf)
|
||||||
|
}
|
||||||
|
// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<()> {
|
||||||
|
// self.file.write_all_vectored(bufs)
|
||||||
|
// }
|
||||||
|
fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()> {
|
||||||
|
self.file.write_fmt(fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SysDirEntry {
|
||||||
|
dir_entry: StdDirEntry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirEntry for SysDirEntry {
|
||||||
|
type Metadata = SysMetadata;
|
||||||
|
|
||||||
|
fn path(&self) -> Result<Utf8PathBuf> {
|
||||||
|
Utf8PathBuf::try_from(
|
||||||
|
self.dir_entry.path()
|
||||||
|
).map_err(as_io_error)
|
||||||
|
}
|
||||||
|
fn metadata(&self) -> Result<Self::Metadata> {
|
||||||
|
Ok(self.dir_entry.metadata()?.into())
|
||||||
|
}
|
||||||
|
fn file_type(&self) -> Result<FileType> {
|
||||||
|
Ok(as_filetype(self.dir_entry.file_type()?))
|
||||||
|
}
|
||||||
|
fn file_name(&self) -> Result<String> {
|
||||||
|
as_string(self.dir_entry.file_name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StdDirEntry> for SysDirEntry {
|
||||||
|
fn from(dir_entry: StdDirEntry) -> Self {
|
||||||
|
SysDirEntry {
|
||||||
|
dir_entry: dir_entry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SysReadDir {
|
||||||
|
read_dir: StdReadDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for SysReadDir {
|
||||||
|
type Item = Result<SysDirEntry>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self.read_dir.next() {
|
||||||
|
Some(Ok(dir_entry)) => Some(Ok(dir_entry.into())),
|
||||||
|
Some(Err(error)) => Some(Err(error)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SysFileSystem;
|
||||||
|
|
||||||
|
impl SysFileSystem {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileSystem for SysFileSystem {
|
||||||
|
type File = SysFile;
|
||||||
|
type DirEntry = SysDirEntry;
|
||||||
|
type ReadDir = SysReadDir;
|
||||||
|
|
||||||
|
fn open_with_options<P: AsRef<Utf8Path>>(&self, path: P, options: &OpenOptions) -> Result<Self::File> {
|
||||||
|
Ok(SysFile{
|
||||||
|
file: StdFile::options()
|
||||||
|
.read(options.is_read())
|
||||||
|
.write(options.is_write())
|
||||||
|
.append(options.is_append())
|
||||||
|
.truncate(options.is_truncate())
|
||||||
|
.create(options.is_create())
|
||||||
|
.create_new(options.is_create_new())
|
||||||
|
.open(path.as_ref().as_std_path())?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_dir<P: AsRef<Utf8Path>>(&self, path: P) -> Result<SysReadDir> {
|
||||||
|
Ok(SysReadDir {
|
||||||
|
read_dir: fs::read_dir(path.as_ref().as_std_path())?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::FileSystem;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file_read_write() {
|
||||||
|
let dir = tempfile::tempdir().expect("failed to create temp test dir");
|
||||||
|
let file_path = Utf8PathBuf::from_path_buf(dir.path().join("test.txt")).unwrap();
|
||||||
|
|
||||||
|
let message = b"Hello world!\nThis is a test\n";
|
||||||
|
|
||||||
|
let fs = SysFileSystem::new();
|
||||||
|
let mut file = fs.create_new(&file_path).unwrap();
|
||||||
|
file.write(message).unwrap();
|
||||||
|
drop(file);
|
||||||
|
|
||||||
|
let mut file = fs.open(&file_path).unwrap();
|
||||||
|
let mut buf = [0u8; 256];
|
||||||
|
let read_size = file.read(&mut buf).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(read_size, message.len());
|
||||||
|
assert_eq!(&buf[..message.len()], message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_dir() {
|
||||||
|
let dir = tempfile::tempdir().expect("failed to create temp test dir");
|
||||||
|
let dir_path = Utf8Path::from_path(dir.path()).unwrap();
|
||||||
|
let file0_path = dir_path.join("file.txt");
|
||||||
|
let file1_path = dir_path.join("zzz.txt");
|
||||||
|
let dir0_path = dir_path.join("some_dir");
|
||||||
|
|
||||||
|
let fs = SysFileSystem::new();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut file = fs.create_new(file0_path).unwrap();
|
||||||
|
file.write(b"file.txt").unwrap();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut file = fs.create_new(file1_path).unwrap();
|
||||||
|
file.write(b"zzz.txt").unwrap();
|
||||||
|
}
|
||||||
|
fs::create_dir(dir0_path).unwrap();
|
||||||
|
|
||||||
|
let mut entries = fs.read_dir(dir_path).unwrap()
|
||||||
|
.collect::<Result<Vec<_>>>().unwrap();
|
||||||
|
entries.sort_by_key(|entry| entry.file_name().unwrap());
|
||||||
|
|
||||||
|
let mut it = entries.iter();
|
||||||
|
|
||||||
|
let file0_entry = it.next().unwrap();
|
||||||
|
assert_eq!(file0_entry.file_name().unwrap(), "file.txt");
|
||||||
|
assert_eq!(file0_entry.file_type().unwrap(), FileType::File);
|
||||||
|
let file0_metadata = file0_entry.metadata().unwrap();
|
||||||
|
assert!(file0_metadata.is_file());
|
||||||
|
assert_eq!(file0_metadata.len(), 8);
|
||||||
|
|
||||||
|
let dir0_entry = it.next().unwrap();
|
||||||
|
assert_eq!(dir0_entry.file_name().unwrap(), "some_dir");
|
||||||
|
assert_eq!(dir0_entry.file_type().unwrap(), FileType::Dir);
|
||||||
|
let dir0_metadata = dir0_entry.metadata().unwrap();
|
||||||
|
assert!(dir0_metadata.is_dir());
|
||||||
|
|
||||||
|
let file1_entry = it.next().unwrap();
|
||||||
|
assert_eq!(file1_entry.file_name().unwrap(), "zzz.txt");
|
||||||
|
assert_eq!(file1_entry.file_type().unwrap(), FileType::File);
|
||||||
|
let file1_metadata = file1_entry.metadata().unwrap();
|
||||||
|
assert!(file1_metadata.is_file());
|
||||||
|
assert_eq!(file1_metadata.len(), 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// This file is part of bsv.
|
||||||
|
//
|
||||||
|
// bsv is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU Affero General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// bsv is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the Affero GNU General Public License
|
||||||
|
// along with bsv. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
extern crate camino;
|
||||||
|
extern crate thiserror;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
extern crate tempfile;
|
||||||
|
|
||||||
|
|
||||||
|
// mod error;
|
||||||
|
mod fs;
|
||||||
|
mod fs_impl;
|
||||||
|
mod mem_fs;
|
||||||
|
|
||||||
|
|
||||||
|
pub use crate::{
|
||||||
|
fs::*,
|
||||||
|
fs_impl::*,
|
||||||
|
};
|
||||||
|
|||||||
468
bsvfs/src/mem_fs.rs
Normal file
468
bsvfs/src/mem_fs.rs
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
// This file is part of bsv.
|
||||||
|
//
|
||||||
|
// bsv is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU Affero General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// bsv is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the Affero GNU General Public License
|
||||||
|
// along with bsv. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt::{Arguments},
|
||||||
|
io::{Cursor, Error, IoSlice, IoSliceMut, Read, Result, Seek, SeekFrom, Write, ErrorKind},
|
||||||
|
time::SystemTime, rc::Rc, cell::RefCell,
|
||||||
|
};
|
||||||
|
|
||||||
|
use camino::{Utf8Path, Utf8PathBuf};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
fs::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct MemMetadata {
|
||||||
|
file_type: FileType,
|
||||||
|
len: u64,
|
||||||
|
permissions: Permissions,
|
||||||
|
modified: SystemTime,
|
||||||
|
created: SystemTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metadata for MemMetadata {
|
||||||
|
fn file_type(&self) -> FileType {
|
||||||
|
self.file_type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> u64 {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permissions(&self) -> Permissions {
|
||||||
|
self.permissions.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modified(&self) -> Result<SystemTime> {
|
||||||
|
Ok(self.modified)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn created(&self) -> Result<SystemTime> {
|
||||||
|
Ok(self.created)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MemFile {
|
||||||
|
metadata: MemMetadata,
|
||||||
|
data: RefCell<Cursor<Vec<u8>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl File for MemFile {
|
||||||
|
type Metadata = MemMetadata;
|
||||||
|
|
||||||
|
// fn open_with_options<P: AsRef<Utf8Path>>(path: P, options: &OpenOptions) -> Result<Self> {
|
||||||
|
// Ok(SysFile{
|
||||||
|
// file: StdFile::options()
|
||||||
|
// .read(options.is_read())
|
||||||
|
// .write(options.is_write())
|
||||||
|
// .append(options.is_append())
|
||||||
|
// .truncate(options.is_truncate())
|
||||||
|
// .create(options.is_create())
|
||||||
|
// .create_new(options.is_create_new())
|
||||||
|
// .open(path.as_ref().as_std_path())?,
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn metadata(&self) -> Result<Self::Metadata> {
|
||||||
|
Ok(self.metadata.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_len(&self, size: u64) -> Result<()> {
|
||||||
|
let mut data = self.data.borrow_mut();
|
||||||
|
let pos = data.position();
|
||||||
|
data.get_mut().resize(size as usize, 0);
|
||||||
|
if size < pos {
|
||||||
|
data.seek(SeekFrom::Start(pos));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_data(&self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_all(&self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for MemFile {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.read_vectored(bufs)
|
||||||
|
}
|
||||||
|
// fn is_read_vectored(&self) -> bool {
|
||||||
|
// self.data.is_read_vectored()
|
||||||
|
// }
|
||||||
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.read_to_end(buf)
|
||||||
|
}
|
||||||
|
fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.read_to_string(buf)
|
||||||
|
}
|
||||||
|
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.read_exact(buf)
|
||||||
|
}
|
||||||
|
// fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
|
||||||
|
// self.data.read_buf(buf)
|
||||||
|
// }
|
||||||
|
// fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> {
|
||||||
|
// self.data.read_buf_exact(cursor)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Seek for MemFile {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.seek(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rewind(&mut self) -> Result<()> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.rewind()
|
||||||
|
}
|
||||||
|
// fn stream_len(&mut self) -> Result<u64> {
|
||||||
|
// self.data.stream_len()
|
||||||
|
// }
|
||||||
|
fn stream_position(&mut self) -> Result<u64> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.stream_position()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for MemFile {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.write(buf)
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> Result<()> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.write_vectored(bufs)
|
||||||
|
}
|
||||||
|
// fn is_write_vectored(&self) -> bool {
|
||||||
|
// self.data.is_write_vectored()
|
||||||
|
// }
|
||||||
|
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.write_all(buf)
|
||||||
|
}
|
||||||
|
// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<()> {
|
||||||
|
// self.data.write_all_vectored(bufs)
|
||||||
|
// }
|
||||||
|
fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()> {
|
||||||
|
let data = self.data.get_mut();
|
||||||
|
data.write_fmt(fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct MemDir {
|
||||||
|
metadata: MemMetadata,
|
||||||
|
items: Vec<Rc<RefCell<DirItem>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemDir {
|
||||||
|
fn new() -> Self {
|
||||||
|
let time = SystemTime::now();
|
||||||
|
Self::new_with_time(&time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_time(time: &SystemTime) -> Self {
|
||||||
|
MemDir {
|
||||||
|
metadata: MemMetadata {
|
||||||
|
file_type: FileType::Dir,
|
||||||
|
len: 0,
|
||||||
|
permissions: Permissions::new(true, true, false),
|
||||||
|
modified: time.clone(),
|
||||||
|
created: time.clone(),
|
||||||
|
},
|
||||||
|
items: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, name: &str) -> Option<&DirItem> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn get_mut(&self, name: &str) -> Option<&mut DirItem> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search(&self, name: &str) -> std::result::Result<usize, usize> {
|
||||||
|
self.items.binary_search_by(
|
||||||
|
|item| item.borrow().name().cmp(name),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum DirItem {
|
||||||
|
Dir(String, MemDir),
|
||||||
|
File(String, MemFile),
|
||||||
|
Err(String, ErrorKind, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirItem {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
DirItem::Dir(ref name, _) => name,
|
||||||
|
DirItem::File(ref name, _) => name,
|
||||||
|
DirItem::Err(ref name, _, _) => name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct MemDirEntry {
|
||||||
|
path: Utf8PathBuf,
|
||||||
|
metadata: MemMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirEntry for MemDirEntry {
|
||||||
|
type Metadata = MemMetadata;
|
||||||
|
|
||||||
|
fn path(&self) -> Result<Utf8PathBuf> {
|
||||||
|
Ok(self.path.clone())
|
||||||
|
}
|
||||||
|
fn metadata(&self) -> Result<Self::Metadata> {
|
||||||
|
Ok(self.metadata.clone())
|
||||||
|
}
|
||||||
|
fn file_type(&self) -> Result<FileType> {
|
||||||
|
Ok(self.metadata.file_type())
|
||||||
|
}
|
||||||
|
fn file_name(&self) -> Result<String> {
|
||||||
|
Ok(self.path.file_name().unwrap().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MemReadDir {
|
||||||
|
base_path: Utf8PathBuf,
|
||||||
|
items: Vec<DirItem>,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for MemReadDir {
|
||||||
|
type Item = Result<MemDirEntry>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self.items.get(self.index) {
|
||||||
|
Some(DirItem::Dir(ref name, ref dir)) => {
|
||||||
|
let mut path = self.base_path.clone();
|
||||||
|
path.push(name);
|
||||||
|
|
||||||
|
self.index += 1;
|
||||||
|
Some(Ok(MemDirEntry{path, metadata: dir.metadata.clone()}))
|
||||||
|
},
|
||||||
|
Some(DirItem::File(ref name, ref file)) => {
|
||||||
|
let mut path = self.base_path.clone();
|
||||||
|
path.push(name);
|
||||||
|
|
||||||
|
self.index += 1;
|
||||||
|
Some(Ok(MemDirEntry{path, metadata: file.metadata.clone()}))
|
||||||
|
},
|
||||||
|
Some(DirItem::Err(_, kind, ref msg)) => {
|
||||||
|
self.index += 1;
|
||||||
|
Some(Err(Error::new(*kind, msg.clone())))
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct MemFileSystem {
|
||||||
|
root: MemDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemFileSystem {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
root: MemDir::new_with_time(&SystemTime::UNIX_EPOCH),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mkdir<P: AsRef<Utf8Path>>(&mut self, path: P, parents: bool, exist_ok: bool) -> Result<()> {
|
||||||
|
use camino::Utf8Component::*;
|
||||||
|
let mut parents = Vec::new();
|
||||||
|
let mut iter = path.as_ref().components();
|
||||||
|
|
||||||
|
match iter.next() {
|
||||||
|
Some(Prefix(_)) => {
|
||||||
|
return make_err("Windows-like path are not supported by MemFileSystem");
|
||||||
|
},
|
||||||
|
Some(RootDir) => {
|
||||||
|
parents.push(&mut self.root);
|
||||||
|
},
|
||||||
|
Some(_) => {
|
||||||
|
return make_err("path must be absolute");
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return make_err("path is empty")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for comp in iter {
|
||||||
|
match comp {
|
||||||
|
Prefix(_) |
|
||||||
|
RootDir => {
|
||||||
|
panic!();
|
||||||
|
},
|
||||||
|
CurDir => {},
|
||||||
|
ParentDir => {
|
||||||
|
if parents.len() <= 1 {
|
||||||
|
return make_err("invalid path")
|
||||||
|
}
|
||||||
|
parents.pop();
|
||||||
|
},
|
||||||
|
Normal(name) => {
|
||||||
|
let maybe_item = parents.last().unwrap().get_mut(name);
|
||||||
|
match maybe_item {
|
||||||
|
Some(DirItem::Dir(_, ref mut dir)) => {
|
||||||
|
parents.push(dir);
|
||||||
|
},
|
||||||
|
Some(DirItem::File(_, _)) => {
|
||||||
|
return make_err("item is a file")
|
||||||
|
}
|
||||||
|
Some(DirItem::Err(_, kind, msg)) => {
|
||||||
|
return Err(std::io::Error::new(*kind, &**msg));
|
||||||
|
}
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_err("TODO")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileSystem for MemFileSystem {
|
||||||
|
type File = MemFile;
|
||||||
|
type DirEntry = MemDirEntry;
|
||||||
|
type ReadDir = MemReadDir;
|
||||||
|
|
||||||
|
fn open_with_options<P: AsRef<Utf8Path>>(&self, path: P, options: &OpenOptions) -> Result<Self::File> {
|
||||||
|
make_err("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_dir<P: AsRef<Utf8Path>>(&self, path: P) -> Result<MemReadDir> {
|
||||||
|
Ok(MemReadDir {
|
||||||
|
base_path: path.as_ref().into(),
|
||||||
|
items: vec![], // TODO
|
||||||
|
index: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn make_error(message: &str) -> std::io::Error {
|
||||||
|
std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
message,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn make_err<T>(message: &str) -> Result<T> {
|
||||||
|
Err(make_error(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
// use camino::Utf8PathBuf;
|
||||||
|
|
||||||
|
// use super::*;
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_file_read_write() {
|
||||||
|
// let dir = tempfile::tempdir().expect("failed to create temp test dir");
|
||||||
|
// let file_path = Utf8PathBuf::from_path_buf(dir.path().join("test.txt")).unwrap();
|
||||||
|
|
||||||
|
// let message = b"Hello world!\nThis is a test\n";
|
||||||
|
|
||||||
|
// let mut file = SysFile::create_new(&file_path).unwrap();
|
||||||
|
// file.write(message).unwrap();
|
||||||
|
// drop(file);
|
||||||
|
|
||||||
|
// let mut file = SysFile::open(&file_path).unwrap();
|
||||||
|
// let mut buf = [0u8; 256];
|
||||||
|
// let read_size = file.read(&mut buf).unwrap();
|
||||||
|
|
||||||
|
// assert_eq!(read_size, message.len());
|
||||||
|
// assert_eq!(&buf[..message.len()], message);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_read_dir() {
|
||||||
|
// let dir = tempfile::tempdir().expect("failed to create temp test dir");
|
||||||
|
// let dir_path = Utf8Path::from_path(dir.path()).unwrap();
|
||||||
|
// let file0_path = dir_path.join("file.txt");
|
||||||
|
// let file1_path = dir_path.join("zzz.txt");
|
||||||
|
// let dir0_path = dir_path.join("some_dir");
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let mut file = SysFile::create_new(file0_path).unwrap();
|
||||||
|
// file.write(b"file.txt").unwrap();
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// let mut file = SysFile::create_new(file1_path).unwrap();
|
||||||
|
// file.write(b"zzz.txt").unwrap();
|
||||||
|
// }
|
||||||
|
// fs::create_dir(dir0_path).unwrap();
|
||||||
|
|
||||||
|
// let mut entries = SysFileSystem::read_dir(dir_path).unwrap()
|
||||||
|
// .collect::<Result<Vec<_>>>().unwrap();
|
||||||
|
// entries.sort_by_key(|entry| entry.file_name().unwrap());
|
||||||
|
|
||||||
|
// let mut it = entries.iter();
|
||||||
|
|
||||||
|
// let file0_entry = it.next().unwrap();
|
||||||
|
// assert_eq!(file0_entry.file_name().unwrap(), "file.txt");
|
||||||
|
// assert_eq!(file0_entry.file_type().unwrap(), FileType::File);
|
||||||
|
// let file0_metadata = file0_entry.metadata().unwrap();
|
||||||
|
// assert!(file0_metadata.is_file());
|
||||||
|
// assert_eq!(file0_metadata.len(), 8);
|
||||||
|
|
||||||
|
// let dir0_entry = it.next().unwrap();
|
||||||
|
// assert_eq!(dir0_entry.file_name().unwrap(), "some_dir");
|
||||||
|
// assert_eq!(dir0_entry.file_type().unwrap(), FileType::Dir);
|
||||||
|
// let dir0_metadata = dir0_entry.metadata().unwrap();
|
||||||
|
// assert!(dir0_metadata.is_dir());
|
||||||
|
|
||||||
|
// let file1_entry = it.next().unwrap();
|
||||||
|
// assert_eq!(file1_entry.file_name().unwrap(), "zzz.txt");
|
||||||
|
// assert_eq!(file1_entry.file_type().unwrap(), FileType::File);
|
||||||
|
// let file1_metadata = file1_entry.metadata().unwrap();
|
||||||
|
// assert!(file1_metadata.is_file());
|
||||||
|
// assert_eq!(file1_metadata.len(), 7);
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -9,5 +9,6 @@ license = "AGPL-3.0-or-later"
|
|||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
camino = "1.0.7"
|
camino = "1.0.7"
|
||||||
regex = "1.6.0"
|
regex = "1.6.0"
|
||||||
|
bsvfs = { path = "../bsvfs" }
|
||||||
cas-core = { path = "../cas-core" }
|
cas-core = { path = "../cas-core" }
|
||||||
cas-simple = { path = "../cas-simple" }
|
cas-simple = { path = "../cas-simple" }
|
||||||
@@ -18,10 +18,11 @@ extern crate toml;
|
|||||||
extern crate camino;
|
extern crate camino;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
|
extern crate bsvfs;
|
||||||
extern crate cas_core;
|
extern crate cas_core;
|
||||||
|
|
||||||
|
|
||||||
mod permissions;
|
// mod permissions;
|
||||||
mod tree_item;
|
mod tree_item;
|
||||||
mod tree_walker;
|
mod tree_walker;
|
||||||
// mod config;
|
// mod config;
|
||||||
@@ -30,7 +31,7 @@ mod ignore;
|
|||||||
mod repository;
|
mod repository;
|
||||||
|
|
||||||
|
|
||||||
pub use crate::permissions::Permissions;
|
// pub use crate::permissions::Permissions;
|
||||||
pub use crate::tree_item::{Serialize, TreeItem};
|
pub use crate::tree_item::{Serialize, TreeItem};
|
||||||
pub use crate::path_map::{PathMap, PathPair};
|
pub use crate::path_map::{PathMap, PathPair};
|
||||||
pub use crate::repository::{Repository};
|
pub use crate::repository::{Repository};
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
// along with bsv. If not, see <https://www.gnu.org/licenses/>.
|
// along with bsv. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
use bsvfs::{Metadata};
|
||||||
use cas_core::{err, Error, Result};
|
use cas_core::{err, Error, Result};
|
||||||
|
|
||||||
|
|
||||||
@@ -25,24 +26,12 @@ pub struct Permissions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Permissions {
|
impl Permissions {
|
||||||
#[cfg(not(unix))]
|
pub fn from_metadata<M: Metadata>(metadata: &M) -> Result<Self> {
|
||||||
pub fn from_metadata(metadata: &std::fs::Metadata) -> Result<Self> {
|
let permissions = metadata.permissions();
|
||||||
if metadata.permissions().readonly() {
|
|
||||||
Ok(Permissions::READ_ONLY)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Ok(Permission::READ_WRITE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn from_metadata(metadata: &std::fs::Metadata) -> Result<Self> {
|
|
||||||
use std::os::unix::fs::MetadataExt;
|
|
||||||
let mode = metadata.mode();
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
read: mode & 0o100 != 0,
|
read: permissions.is_read(),
|
||||||
write: mode & 0o200 != 0,
|
write: permissions.is_write(),
|
||||||
execute: mode & 0o400 != 0,
|
execute: permissions.is_execute(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ use toml::Value;
|
|||||||
use cas_core::{Cas, err, Error, ObjectId, Result};
|
use cas_core::{Cas, err, Error, ObjectId, Result};
|
||||||
use cas_simple::{SimpleCas};
|
use cas_simple::{SimpleCas};
|
||||||
|
|
||||||
pub use crate::permissions::Permissions;
|
|
||||||
pub use crate::tree_item::{Serialize, TreeItem};
|
pub use crate::tree_item::{Serialize, TreeItem};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,9 @@
|
|||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
use std::io::{BufRead, Write};
|
use std::io::{BufRead, Write};
|
||||||
|
|
||||||
|
use bsvfs::{Metadata, Permissions};
|
||||||
use cas_core::{err, Error, ObjectId, ObjectType, Result};
|
use cas_core::{err, Error, ObjectId, ObjectType, Result};
|
||||||
|
|
||||||
use crate::Permissions;
|
|
||||||
|
|
||||||
|
|
||||||
pub trait Serialize {
|
pub trait Serialize {
|
||||||
fn serialize<W: Write>(&self, out: &mut W) -> Result<()>;
|
fn serialize<W: Write>(&self, out: &mut W) -> Result<()>;
|
||||||
@@ -51,9 +50,10 @@ pub struct TreeItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TreeItem {
|
impl TreeItem {
|
||||||
pub fn from_metadata(name: String, metadata: &std::fs::Metadata, oid: ObjectId) -> Result<Self> {
|
// pub fn from_metadata(name: String, metadata: &std::fs::Metadata, oid: ObjectId) -> Result<Self> {
|
||||||
|
pub fn from_metadata<M: Metadata>(name: String, metadata: &M, oid: ObjectId) -> Result<Self> {
|
||||||
let otype = otype_from_metadata(metadata)?;
|
let otype = otype_from_metadata(metadata)?;
|
||||||
let permissions = Permissions::from_metadata(metadata)?;
|
let permissions = metadata.permissions();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: name,
|
name: name,
|
||||||
@@ -134,7 +134,7 @@ impl Serialize for [TreeItem] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn otype_from_metadata(metadata: &std::fs::Metadata) -> Result<ObjectType> {
|
pub fn otype_from_metadata<M: Metadata>(metadata: &M) -> Result<ObjectType> {
|
||||||
let file_type = metadata.file_type();
|
let file_type = metadata.file_type();
|
||||||
|
|
||||||
if file_type.is_file() {
|
if file_type.is_file() {
|
||||||
@@ -193,7 +193,7 @@ mod tests {
|
|||||||
size: 42,
|
size: 42,
|
||||||
created: UNIX_EPOCH + Duration::from_secs(1234),
|
created: UNIX_EPOCH + Duration::from_secs(1234),
|
||||||
modified: UNIX_EPOCH + Duration::from_secs(5678),
|
modified: UNIX_EPOCH + Duration::from_secs(5678),
|
||||||
permissions: Permissions { read: true, write: false, execute: true },
|
permissions: Permissions::new(true, false, true),
|
||||||
oid: ObjectId::from_str("0123456789abcdef").unwrap(),
|
oid: ObjectId::from_str("0123456789abcdef").unwrap(),
|
||||||
};
|
};
|
||||||
let expected = "0123456789abcdef\ttest\t42\tr-x\t1234000\t5678000\tTest $¢ह€한/\n".as_bytes();
|
let expected = "0123456789abcdef\ttest\t42\tr-x\t1234000\t5678000\tTest $¢ह€한/\n".as_bytes();
|
||||||
@@ -216,7 +216,7 @@ mod tests {
|
|||||||
size: 42,
|
size: 42,
|
||||||
created: UNIX_EPOCH + Duration::from_secs(1234),
|
created: UNIX_EPOCH + Duration::from_secs(1234),
|
||||||
modified: UNIX_EPOCH + Duration::from_secs(5678),
|
modified: UNIX_EPOCH + Duration::from_secs(5678),
|
||||||
permissions: Permissions { read: true, write: false, execute: true },
|
permissions: Permissions::new(true, false, true),
|
||||||
oid: ObjectId::from_str("0123456789abcdef").unwrap(),
|
oid: ObjectId::from_str("0123456789abcdef").unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,15 @@
|
|||||||
|
|
||||||
|
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::fs::{DirEntry, Metadata, ReadDir, read_dir};
|
// use std::fs::{DirEntry, Metadata, ReadDir, read_dir};
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use camino::{Utf8Path};
|
||||||
|
|
||||||
use cas_core::{err, Error, ObjectId, Result};
|
use bsvfs::{DirEntry, FileSystem};
|
||||||
|
use cas_core::{ObjectId, Result};
|
||||||
|
|
||||||
use crate::{PathPair, Repository, TreeItem};
|
use crate::{TreeItem};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -31,7 +32,7 @@ pub enum Action {
|
|||||||
Update,
|
Update,
|
||||||
Remove,
|
Remove,
|
||||||
Skip,
|
Skip,
|
||||||
Ignore,
|
// Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TreeWalker {
|
pub struct TreeWalker {
|
||||||
@@ -41,18 +42,14 @@ pub struct TreeWalker {
|
|||||||
|
|
||||||
|
|
||||||
impl TreeWalker {
|
impl TreeWalker {
|
||||||
pub fn new<P: AsRef<Utf8Path>>(path: P, prev_tree: Vec<TreeItem>) -> Result<Self> {
|
pub fn new<Fs: FileSystem, P: AsRef<Utf8Path>>(fs: Fs, path: P, prev_tree: Vec<TreeItem>) -> Result<Self> {
|
||||||
let dir_entries = read_dir(path.as_ref().to_path_buf())?
|
let dir_entries = fs.read_dir(path.as_ref().to_path_buf())?
|
||||||
.map(|res| res.map_err(|err| err.into()))
|
.map(|res| res.map_err(|err| err.into()))
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let mut dir_items: Vec<_> = dir_entries.into_iter()
|
let mut dir_items: Vec<_> = dir_entries.into_iter()
|
||||||
.map(|dir_entry| {
|
.map(|dir_entry| {
|
||||||
let file_name = dir_entry
|
let file_name = dir_entry.file_name()?;
|
||||||
.file_name()
|
|
||||||
.into_string()
|
|
||||||
// .or_else(|os_string| err!("non-unicode file name '{}'", os_string.to_string_lossy()))?;
|
|
||||||
.or_else(|os_string| Err(Error::NonUnicodeFileName(os_string.to_string_lossy().into())))?;
|
|
||||||
let metadata = dir_entry.metadata()?;
|
let metadata = dir_entry.metadata()?;
|
||||||
Ok(TreeItem::from_metadata(
|
Ok(TreeItem::from_metadata(
|
||||||
file_name,
|
file_name,
|
||||||
@@ -117,11 +114,13 @@ impl Iterator for TreeWalker {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use bsvfs::SysFileSystem;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tree_walker() {
|
fn test_tree_walker() {
|
||||||
for item in TreeWalker::new("/home/draklaw/tmp", vec![]).unwrap() {
|
for item in TreeWalker::new(SysFileSystem::new(), "/home/draklaw/tmp", vec![]).unwrap() {
|
||||||
match item {
|
match item {
|
||||||
Ok((action, tree_item)) => println!("{:?} {:?}", action, tree_item.name),
|
Ok((action, tree_item)) => println!("{:?} {:?}", action, tree_item.name),
|
||||||
Err(err) => println!("error while iterating directory: {}", err),
|
Err(err) => println!("error while iterating directory: {}", err),
|
||||||
|
|||||||
Reference in New Issue
Block a user