Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • redox-os/redoxfs
  • jD91mZM2/redoxfs
  • microcolonel/redoxfs
  • rm-dr/redoxfs
  • deepaksirone/redoxfs
  • sevenEng/redoxfs
  • mortona/redoxfs
  • potatogim/redoxfs
  • 4lDO2/redoxfs
  • malandrakisgeo/redoxfs
  • ssd/redoxfs
  • dahc/redoxfs
  • ashton/redoxfs
  • usapmz/redoxfs
  • vadorovsky/redoxfs
  • bjorn3/redoxfs
  • rw_van/redoxfs
  • mkroening/redoxfs
  • emaxx-g/redoxfs
  • CILP/redoxfs
  • AnandSMain/redoxfs
  • aaronjanse/redoxfs
  • liamnprg/redoxfs
  • coolreader18/redoxfs
  • freewilll/redoxfs
  • adi-g15/redoxfs
  • andrey.turkin/redoxfs
  • matlik/redoxfs
28 results
Show changes
Commits on Source (88)
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]]
name = "addr2line"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "aes" name = "aes"
...@@ -31,47 +16,70 @@ dependencies = [ ...@@ -31,47 +16,70 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.20" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]] [[package]]
name = "argon2" name = "anstream"
version = "0.3.4" version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25df3c03f1040d0069fcd3907e24e36d59f9b6fa07ba49be0eb25a794f036ba7" checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
dependencies = [ dependencies = [
"base64ct", "anstyle",
"blake2", "anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
] ]
[[package]] [[package]]
name = "atty" name = "anstyle"
version = "0.2.14" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [ dependencies = [
"hermit-abi", "utf8parse",
"libc",
"winapi",
] ]
[[package]] [[package]]
name = "backtrace" name = "anstyle-query"
version = "0.3.67" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [ dependencies = [
"addr2line", "windows-sys",
"cc", ]
"cfg-if",
"libc", [[package]]
"miniz_oxide", name = "anstyle-wincon"
"object", version = "3.0.6"
"rustc-demangle", source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "argon2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73"
dependencies = [
"base64ct",
"blake2",
] ]
[[package]] [[package]]
...@@ -82,9 +90,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" ...@@ -82,9 +90,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]] [[package]]
name = "blake2" name = "blake2"
...@@ -106,15 +114,9 @@ dependencies = [ ...@@ -106,15 +114,9 @@ dependencies = [
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
...@@ -131,11 +133,17 @@ dependencies = [ ...@@ -131,11 +133,17 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.6" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [ dependencies = [
"libc", "libc",
] ]
...@@ -150,11 +158,20 @@ dependencies = [ ...@@ -150,11 +158,20 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.6" version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"crypto-common", "crypto-common",
...@@ -162,51 +179,39 @@ dependencies = [ ...@@ -162,51 +179,39 @@ dependencies = [
] ]
[[package]] [[package]]
name = "env_logger" name = "endian-num"
version = "0.9.3" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" checksum = "f8f59926911ef34d1efb9ea1ee8ca78385df62ce700ccf2bcb149011bd226888"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]] [[package]]
name = "failure" name = "env_filter"
version = "0.1.8" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
dependencies = [ dependencies = [
"backtrace", "log",
"failure_derive", "regex",
] ]
[[package]] [[package]]
name = "failure_derive" name = "env_logger"
version = "0.1.8" version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
dependencies = [ dependencies = [
"proc-macro2", "anstream",
"quote", "anstyle",
"syn", "env_filter",
"synstructure", "humantime",
"log",
] ]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]] [[package]]
name = "fuser" name = "fuser"
version = "0.12.0" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5910691a0ececcc6eba8bb14029025c2d123e96a53db1533f6a4602861a5aaf7" checksum = "2e697f6f62c20b6fad1ba0f84ae909f25971cf16e735273524e3977c94604cf8"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
...@@ -214,7 +219,6 @@ dependencies = [ ...@@ -214,7 +219,6 @@ dependencies = [
"page_size", "page_size",
"pkg-config", "pkg-config",
"smallvec", "smallvec",
"users",
"zerocopy", "zerocopy",
] ]
...@@ -230,28 +234,13 @@ dependencies = [ ...@@ -230,28 +234,13 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.9" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"wasi 0.11.0+wasi-snapshot-preview1", "wasi",
]
[[package]]
name = "gimli"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
] ]
[[package]] [[package]]
...@@ -260,62 +249,64 @@ version = "2.1.0" ...@@ -260,62 +249,64 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.141" version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]] [[package]]
name = "log" name = "libredox"
version = "0.4.17" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [ dependencies = [
"cfg-if", "bitflags",
"libc",
"redox_syscall",
] ]
[[package]] [[package]]
name = "memchr" name = "log"
version = "2.5.0" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]] [[package]]
name = "miniz_oxide" name = "memchr"
version = "0.6.2" version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
dependencies = [
"adler",
]
[[package]] [[package]]
name = "numtoa" name = "num-conv"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]] [[package]]
name = "object" name = "numtoa"
version = "0.30.3" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
version = "0.3.0" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]] [[package]]
name = "page_size" name = "page_size"
version = "0.4.2" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
dependencies = [ dependencies = [
"libc", "libc",
"winapi", "winapi",
...@@ -323,113 +314,88 @@ dependencies = [ ...@@ -323,113 +314,88 @@ dependencies = [
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.26" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.56" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.26" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "rand" name = "range-tree"
version = "0.3.23" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" checksum = "384c2842d4e069d5ccacf5fe1dca4ef8d07a5444329715f0fc3c61813502d4d1"
dependencies = [
"libc",
"rand 0.4.6",
]
[[package]] [[package]]
name = "rand" name = "redox-path"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand_core"
version = "0.3.1" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]] [[package]]
name = "rdrand" name = "redox-scheme"
version = "0.4.0" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" checksum = "6143c4d307e1c99ac14f60b5b07b2dccaf9d17137f7cee4e4e29977dd8014a1b"
dependencies = [ dependencies = [
"rand_core 0.3.1", "libredox",
"redox_syscall",
] ]
[[package]]
name = "redox_simple_endian"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175b27da3d5db1502bd20ae0917ba132d256a2b169f1686681304ebb86504eab"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.16" version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [ dependencies = [
"bitflags", "bitflags",
] ]
[[package]] [[package]]
name = "redox_termios" name = "redox_termios"
version = "0.1.2" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
dependencies = [
"redox_syscall",
]
[[package]] [[package]]
name = "redoxfs" name = "redoxfs"
version = "0.5.7" version = "0.6.9"
dependencies = [ dependencies = [
"aes", "aes",
"argon2", "argon2",
"base64ct", "base64ct",
"endian-num",
"env_logger", "env_logger",
"failure",
"fuser", "fuser",
"getrandom", "getrandom",
"libc", "libc",
"libredox",
"log", "log",
"redox_simple_endian", "range-tree",
"redox-path",
"redox-scheme",
"redox_syscall", "redox_syscall",
"seahash", "seahash",
"termion", "termion",
...@@ -439,26 +405,32 @@ dependencies = [ ...@@ -439,26 +405,32 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.7.3" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata",
"regex-syntax", "regex-syntax",
] ]
[[package]] [[package]]
name = "regex-syntax" name = "regex-automata"
version = "0.6.29" version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]] [[package]]
name = "rustc-demangle" name = "regex-syntax"
version = "0.1.22" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "seahash" name = "seahash"
...@@ -467,120 +439,111 @@ source = "registry+https://github.com/rust-lang/crates.io-index" ...@@ -467,120 +439,111 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]] [[package]]
name = "smallvec" name = "serde"
version = "1.10.0" version = "1.0.214"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [ dependencies = [
"proc-macro2", "serde_derive",
"quote",
"unicode-ident",
] ]
[[package]] [[package]]
name = "synstructure" name = "serde_derive"
version = "0.12.6" version = "1.0.214"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
"unicode-xid",
] ]
[[package]] [[package]]
name = "termcolor" name = "smallvec"
version = "1.2.0" version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [ dependencies = [
"winapi-util", "proc-macro2",
"quote",
"unicode-ident",
] ]
[[package]] [[package]]
name = "termion" name = "termion"
version = "1.5.6" version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" checksum = "7eaa98560e51a2cf4f0bb884d8b2098a9ea11ecf3b7078e9c68242c74cc923a7"
dependencies = [ dependencies = [
"libc", "libc",
"libredox",
"numtoa", "numtoa",
"redox_syscall",
"redox_termios", "redox_termios",
] ]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.45" version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [ dependencies = [
"libc", "deranged",
"wasi 0.10.0+wasi-snapshot-preview1", "num-conv",
"winapi", "powerfmt",
"serde",
"time-core",
] ]
[[package]] [[package]]
name = "typenum" name = "time-core"
version = "1.16.0" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]] [[package]]
name = "unicode-ident" name = "typenum"
version = "1.0.8" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-ident"
version = "0.2.4" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]] [[package]]
name = "users" name = "utf8parse"
version = "0.11.0" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
dependencies = [
"libc",
"log",
]
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "0.5.1" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
dependencies = [ dependencies = [
"rand 0.3.23", "getrandom",
] ]
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]] [[package]]
name = "wasi" name = "wasi"
...@@ -605,25 +568,89 @@ source = "registry+https://github.com/rust-lang/crates.io-index" ...@@ -605,25 +568,89 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]] [[package]]
name = "winapi-util" name = "winapi-x86_64-pc-windows-gnu"
version = "0.1.5" 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 = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [ dependencies = [
"winapi", "windows-targets",
] ]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "windows-targets"
version = "0.4.0" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.6.1" version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"zerocopy-derive", "zerocopy-derive",
...@@ -631,9 +658,9 @@ dependencies = [ ...@@ -631,9 +658,9 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.3.2" version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
name = "redoxfs" name = "redoxfs"
description = "The Redox Filesystem" description = "The Redox Filesystem"
repository = "https://gitlab.redox-os.org/redox-os/redoxfs" repository = "https://gitlab.redox-os.org/redox-os/redoxfs"
version = "0.5.7" version = "0.6.9"
license-file = "LICENSE" license-file = "LICENSE"
readme = "README.md" readme = "README.md"
authors = ["Jeremy Soller <jackpot51@gmail.com>"] authors = ["Jeremy Soller <jackpot51@gmail.com>"]
edition = "2018" edition = "2021"
[lib] [lib]
name = "redoxfs" name = "redoxfs"
...@@ -32,29 +32,24 @@ required-features = ["std"] ...@@ -32,29 +32,24 @@ required-features = ["std"]
[dependencies] [dependencies]
aes = { version = "=0.7.5", default-features = false } aes = { version = "=0.7.5", default-features = false }
argon2 = { version = "0.3.4", default-features = false, features = ["alloc"] } argon2 = { version = "0.4", default-features = false, features = ["alloc"] }
base64ct = { version = "1", default-features = false } base64ct = { version = "1", default-features = false }
env_logger = { version = "0.9.0", optional = true } env_logger = { version = "0.11", optional = true }
failure = "0.1.8" endian-num = "0.1"
getrandom = { version = "0.2.5", optional = true } getrandom = { version = "0.2.5", optional = true }
libc = "0.2" libc = "0.2"
log = { version = "0.4.14", default-features = false, optional = true} log = { version = "0.4.14", default-features = false, optional = true}
redox_syscall = "0.2.12" redox_syscall = { version = "0.5" }
range-tree = { version = "0.1", optional = true }
seahash = { version = "4.1.0", default-features = false } seahash = { version = "4.1.0", default-features = false }
termion = { version = "1.5.6", optional = true } termion = { version = "4", optional = true }
uuid = { version = "0.5", default-features = false } uuid = { version = "1.4", default-features = false }
redox-path = "0.3.0"
# https://github.com/rexlunae/simple-endian-rs/pull/5 libredox = { version = "0.1.3", optional = true }
[dependencies.redox_simple_endian] redox-scheme = { version = "0.2.1", optional = true }
version = "0.3.0"
default-features = false
features = [
"bitwise", "comparisons", "format", "math_ops", "neg_ops", "shift_ops",
"both_endian", "float_impls", "integer_impls", "byte_impls"
]
[features] [features]
default = ["std"] default = ["std", "log"]
force-soft = [ force-soft = [
"aes/force-soft" "aes/force-soft"
] ]
...@@ -63,12 +58,19 @@ std = [ ...@@ -63,12 +58,19 @@ std = [
"fuser", "fuser",
"getrandom", "getrandom",
"libc", "libc",
"libredox",
"range-tree",
"termion", "termion",
"time", "time",
"uuid/v4" "uuid/v4",
"redox_syscall/std",
"redox-scheme"
] ]
[target.'cfg(not(target_os = "redox"))'.dependencies] [target.'cfg(not(target_os = "redox"))'.dependencies]
fuser = { version = "0.12.0", optional = true } fuser = { version = "0.14", optional = true }
libc = { version = "0.2", optional = true } libc = { version = "0.2", optional = true }
time = { version = "0.1", optional = true } time = { version = "0.3", optional = true }
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] }
...@@ -14,8 +14,8 @@ else ...@@ -14,8 +14,8 @@ else
endif endif
image.bin: image.bin:
dd if=/dev/zero of=image.bin bs=1048576 count=1024
cargo build --release --bin redoxfs-mkfs cargo build --release --bin redoxfs-mkfs
dd if=/dev/zero of=image.bin bs=1048576 count=1024
target/release/redoxfs-mkfs image.bin target/release/redoxfs-mkfs image.bin
mount: image.bin FORCE mount: image.bin FORCE
......
# redoxfs # RedoxFS
The Redox Filesystem. Compatible with Redox and Linux.
This is the default filesystem of Redox OS inspired by [ZFS](https://docs.freebsd.org/en/books/handbook/zfs/) and adapted to a microkernel architecture.
(It's a replacement for [TFS](https://gitlab.redox-os.org/redox-os/tfs))
Current features:
- Compatible with Redox and Linux (FUSE)
- Copy-on-write
- Data/metadata checksums
- Transparent encryption
- Standard Unix file attributes
- File/directory size limit up to 193TiB (212TB)
- File/directory quantity limit up to 4 billion per 193TiB (2^32 - 1 = 4294967295)
- MIT licensed
- Disk encryption fully supported by the Redox bootloader, letting it load the kernel off an encrypted partition.
Being MIT licensed, RedoxFS can be bundled on GPL-licensed operating systems (Linux, for example).
### How to mount a partition
- Install RedoxFS
```sh
cargo install redoxfs
```
You can also build RedoxFS from this repository.
- Configure your storage device to allow rootless usage
If you are on Linux you need root permission to acess block devices (storage), but it's recommended to run RedoxFS as rootless.
To do that you need to configure your storage device permission to your user with the following command:
```sh
sudo setfacl -m u:your-username:rw /path/to/disk
```
- Mount your RedoxFS partition
```sh
redoxfs /path/to/disk /path/to/mount
```
[![Travis Build Status](https://travis-ci.org/redox-os/redoxfs.svg?branch=master)](https://travis-ci.org/redox-os/redoxfs)
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
[![crates.io](http://meritbadge.herokuapp.com/redoxfs)](https://crates.io/crates/redoxfs) [![crates.io](http://meritbadge.herokuapp.com/redoxfs)](https://crates.io/crates/redoxfs)
[![docs.rs](https://docs.rs/redoxfs/badge.svg)](https://docs.rs/redoxfs) [![docs.rs](https://docs.rs/redoxfs/badge.svg)](https://docs.rs/redoxfs)
target
corpus
artifacts
coverage
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
"opaque-debug",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "argon2"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25df3c03f1040d0069fcd3907e24e36d59f9b6fa07ba49be0eb25a794f036ba7"
dependencies = [
"base64ct",
"blake2",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
dependencies = [
"jobserver",
"libc",
"once_cell",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
"generic-array",
]
[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "endian-num"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad847bb2094f110bbdd6fa564894ca4556fd978958e93985420d680d3cb6d14"
[[package]]
name = "env_logger"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "fuser"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5910691a0ececcc6eba8bb14029025c2d123e96a53db1533f6a4602861a5aaf7"
dependencies = [
"libc",
"log",
"memchr",
"page_size",
"pkg-config",
"smallvec",
"users",
"zerocopy",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "jobserver"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libfuzzer-sys"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
dependencies = [
"arbitrary",
"cc",
"once_cell",
]
[[package]]
name = "libredox"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
dependencies = [
"bitflags 2.5.0",
"libc",
"redox_syscall 0.4.1",
]
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.5.0",
"libc",
"redox_syscall 0.5.2",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.5.0",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "page_size"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "pkg-config"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "proc-macro2"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "range-tree"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384c2842d4e069d5ccacf5fe1dca4ef8d07a5444329715f0fc3c61813502d4d1"
[[package]]
name = "redox-path"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "redox_termios"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
[[package]]
name = "redoxfs"
version = "0.6.4"
dependencies = [
"aes",
"argon2",
"base64ct",
"endian-num",
"env_logger",
"fuser",
"getrandom",
"libc",
"libredox 0.1.3",
"log",
"range-tree",
"redox-path",
"redox_syscall 0.5.2",
"seahash",
"termion",
"time",
"uuid",
]
[[package]]
name = "redoxfs-fuzz"
version = "0.0.0"
dependencies = [
"anyhow",
"arbitrary",
"fuser",
"libfuzzer-sys",
"nix",
"redoxfs",
"tempfile",
]
[[package]]
name = "regex"
version = "1.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "rustix"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"bitflags 2.5.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [
"cfg-if",
"fastrand",
"rustix",
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "termion"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4648c7def6f2043b2568617b9f9b75eae88ca185dbc1f1fda30e95a85d49d7d"
dependencies = [
"libc",
"libredox 0.0.2",
"numtoa",
"redox_termios",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "users"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
dependencies = [
"libc",
"log",
]
[[package]]
name = "uuid"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
dependencies = [
"getrandom",
]
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "zerocopy"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[package]
name = "redoxfs-fuzz"
version = "0.0.0"
publish = false
edition = "2021"
[features]
default = []
log = []
[package.metadata]
cargo-fuzz = true
[dependencies]
anyhow = "1.0.86"
arbitrary = { version = "1.3.2", features = ["derive"] }
fuser = { version = "0.12.0" }
libfuzzer-sys = "0.4"
nix = { version = "0.29.0", features = ["fs"] }
tempfile = "3.10.1"
[dependencies.redoxfs]
path = ".."
[[bin]]
name = "fuse_fuzz_target"
path = "fuzz_targets/fuse_fuzz_target.rs"
test = false
doc = false
bench = false
//! Fuzzer that exercises random file system operations against a FUSE-mounted redoxfs.
#![no_main]
use anyhow::{ensure, Result};
use fuser;
use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target, Corpus};
use nix::sys::statvfs::statvfs;
use std::{
fs::{self, File, FileTimes, OpenOptions},
io::{Read, Seek, SeekFrom, Write},
os::unix::fs::{self as unix_fs, PermissionsExt},
path::{Path, PathBuf},
thread,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use tempfile;
use redoxfs::{mount::fuse::Fuse, DiskSparse, FileSystem};
/// Maximum size for files and buffers. Chosen arbitrarily with fuzzing performance in mind.
const MAX_SIZE: u64 = 10_000_000;
/// Limit on the number of remounts in a single test case. Chosen arbitrarily with fuzzing
/// performance in mind: remounts are costly.
const MAX_MOUNT_SEQUENCES: usize = 3;
/// An operation to be performed by the fuzzer.
#[derive(Arbitrary, Clone, Debug)]
enum Operation {
Chown {
path: PathBuf,
uid: Option<u32>,
gid: Option<u32>,
},
CreateDir {
path: PathBuf,
},
HardLink {
original: PathBuf,
link: PathBuf,
},
Metadata {
path: PathBuf,
},
Read {
path: PathBuf,
},
ReadDir {
path: PathBuf,
},
ReadLink {
path: PathBuf,
},
RemoveDir {
path: PathBuf,
},
RemoveFile {
path: PathBuf,
},
Rename {
from: PathBuf,
to: PathBuf,
},
SeekRead {
path: PathBuf,
seek_pos: u64,
buf_size: usize,
},
SeekWrite {
path: PathBuf,
seek_pos: u64,
buf_size: usize,
},
SetLen {
path: PathBuf,
size: u64,
},
SetPermissions {
path: PathBuf,
readonly: Option<bool>,
mode: Option<u32>,
},
SetTimes {
path: PathBuf,
accessed_since_epoch: Option<Duration>,
modified_since_epoch: Option<Duration>,
},
Statvfs {},
SymLink {
original: PathBuf,
link: PathBuf,
},
Write {
path: PathBuf,
buf_size: usize,
},
}
/// Parameters for mounting the file system and operations to be performed afterwards.
#[derive(Arbitrary, Clone, Debug)]
struct MountSequence {
squash: bool,
operations: Vec<Operation>,
}
/// The whole input to a single fuzzer invocation.
#[derive(Arbitrary, Clone, Debug)]
struct TestCase {
disk_size: u64,
reserved_size: u64,
mount_sequences: Vec<MountSequence>,
}
/// Creates the disk for backing the Redoxfs.
fn create_disk(temp_path: &Path, disk_size: u64) -> DiskSparse {
let disk_path = temp_path.join("disk.img");
DiskSparse::create(disk_path, disk_size).unwrap()
}
/// Creates an empty Redoxfs.
fn create_redoxfs(disk: DiskSparse, reserved_size: u64) -> bool {
let password = None;
let reserved = vec![0; reserved_size as usize];
let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
FileSystem::create_reserved(
disk,
password,
&reserved,
ctime.as_secs(),
ctime.subsec_nanos(),
)
.is_ok()
}
/// Mounts an existing Redoxfs, runs the callback and performs the unmount.
fn with_redoxfs_mount<F>(temp_path: &Path, disk: DiskSparse, squash: bool, callback: F)
where
F: FnOnce(&Path) + Send + 'static,
{
let password = None;
let block = None;
let mut fs = FileSystem::open(disk, password, block, squash).unwrap();
let mount_path = temp_path.join("mount");
fs::create_dir_all(&mount_path).unwrap();
let mut session = fuser::Session::new(Fuse { fs: &mut fs }, &mount_path, &[]).unwrap();
let mut unmounter = session.unmount_callable();
let join_handle = thread::spawn(move || {
callback(&mount_path);
unmounter.unmount().unwrap();
});
session.run().unwrap();
join_handle.join().unwrap();
}
fn get_path_within_fs(fs_path: &Path, path_to_add: &Path) -> Result<PathBuf> {
ensure!(path_to_add.is_relative());
ensure!(path_to_add
.components()
.all(|c| c != std::path::Component::ParentDir));
Ok(fs_path.join(path_to_add))
}
fn do_operation(fs_path: &Path, op: &Operation) -> Result<()> {
match op {
Operation::Chown { path, uid, gid } => {
let path = get_path_within_fs(fs_path, path)?;
unix_fs::chown(path, *uid, *gid)?;
}
Operation::CreateDir { path } => {
let path = get_path_within_fs(fs_path, path)?;
fs::create_dir(path)?;
}
Operation::HardLink { original, link } => {
let original = get_path_within_fs(fs_path, original)?;
let link = get_path_within_fs(fs_path, link)?;
fs::hard_link(original, link)?;
}
Operation::Metadata { path } => {
let path = get_path_within_fs(fs_path, path)?;
fs::metadata(path)?;
}
Operation::Read { path } => {
let path = get_path_within_fs(fs_path, path)?;
fs::read(path)?;
}
Operation::ReadDir { path } => {
let path = get_path_within_fs(fs_path, path)?;
let _ = fs::read_dir(path)?.count();
}
Operation::ReadLink { path } => {
let path = get_path_within_fs(fs_path, path)?;
fs::read_link(path)?;
}
Operation::RemoveDir { path } => {
let path = get_path_within_fs(fs_path, path)?;
fs::remove_dir(path)?;
}
Operation::RemoveFile { path } => {
let path = get_path_within_fs(fs_path, path)?;
fs::remove_file(path)?;
}
Operation::Rename { from, to } => {
let from = get_path_within_fs(fs_path, from)?;
let to = get_path_within_fs(fs_path, to)?;
fs::rename(from, to)?;
}
Operation::SeekRead {
path,
seek_pos,
buf_size,
} => {
ensure!(*buf_size as u64 <= MAX_SIZE);
let path = get_path_within_fs(fs_path, path)?;
let mut file = File::open(path)?;
file.seek(SeekFrom::Start(*seek_pos))?;
let mut buf = vec![0; *buf_size];
file.read(&mut buf)?;
}
Operation::SeekWrite {
path,
seek_pos,
buf_size,
} => {
ensure!(*seek_pos <= MAX_SIZE);
ensure!(*buf_size as u64 <= MAX_SIZE);
let path = get_path_within_fs(fs_path, path)?;
let mut file = OpenOptions::new().write(true).open(path)?;
file.seek(SeekFrom::Start(*seek_pos))?;
let buf = vec![0; *buf_size];
file.write(&buf)?;
}
Operation::SetLen { path, size } => {
let path = get_path_within_fs(fs_path, path)?;
let file = OpenOptions::new().write(true).open(path)?;
file.set_len(*size)?;
}
Operation::SetPermissions {
path,
readonly,
mode,
} => {
let path = get_path_within_fs(fs_path, path)?;
let metadata = fs::metadata(&path)?;
let mut perms = metadata.permissions();
if let Some(readonly) = readonly {
perms.set_readonly(*readonly);
}
if let Some(mode) = mode {
perms.set_mode(*mode);
}
fs::set_permissions(path, perms)?;
}
Operation::SetTimes {
path,
accessed_since_epoch,
modified_since_epoch,
} => {
let path = get_path_within_fs(fs_path, path)?;
let file = File::options().write(true).open(path)?;
let mut times = FileTimes::new();
if let Some(accessed_since_epoch) = accessed_since_epoch {
if let Some(accessed) = UNIX_EPOCH.checked_add(*accessed_since_epoch) {
times = times.set_accessed(accessed);
}
}
if let Some(modified_since_epoch) = modified_since_epoch {
if let Some(modified) = UNIX_EPOCH.checked_add(*modified_since_epoch) {
times = times.set_modified(modified);
}
}
file.set_times(times)?;
}
Operation::Statvfs {} => {
statvfs(fs_path)?;
}
Operation::SymLink { original, link } => {
let original = get_path_within_fs(fs_path, original)?;
let link = get_path_within_fs(fs_path, link)?;
unix_fs::symlink(original, link)?;
}
Operation::Write { path, buf_size } => {
ensure!(*buf_size as u64 <= MAX_SIZE);
let path = get_path_within_fs(fs_path, path)?;
let buf = vec![0; *buf_size];
fs::write(path, &buf)?;
}
}
Ok(())
}
fuzz_target!(|test_case: TestCase| -> Corpus {
if test_case.disk_size > MAX_SIZE
|| test_case.reserved_size > MAX_SIZE
|| test_case.mount_sequences.len() > MAX_MOUNT_SEQUENCES
{
return Corpus::Reject;
}
let temp_dir = tempfile::Builder::new()
.prefix("fuse_fuzz_target")
.tempdir()
.unwrap();
#[cfg(feature = "log")]
eprintln!("create fs");
let disk = create_disk(temp_dir.path(), test_case.disk_size);
if !create_redoxfs(disk, test_case.reserved_size) {
// File system creation failed (e.g., due to insufficient space) so we bail out, still
// exercising this code path is useful.
return Corpus::Keep;
}
for mount_seq in test_case.mount_sequences.iter() {
#[cfg(feature = "log")]
eprintln!("mount fs");
let disk = create_disk(temp_dir.path(), test_case.disk_size);
let operations = mount_seq.operations.clone();
with_redoxfs_mount(temp_dir.path(), disk, mount_seq.squash, move |fs_path| {
for operation in operations.iter() {
#[cfg(feature = "log")]
eprintln!("do operation {operation:?}");
let _result = do_operation(fs_path, operation);
#[cfg(feature = "log")]
eprintln!("operation result {:?}", _result.err());
}
});
#[cfg(feature = "log")]
eprintln!("unmounted fs");
}
Corpus::Keep
});
use alloc::vec::Vec; use alloc::vec::Vec;
use core::{fmt, mem, ops, slice}; use core::{fmt, mem, ops, slice};
use simple_endian::*; use endian_num::Le;
use crate::BlockPtr; use crate::{BlockAddr, BlockLevel, BlockPtr, BlockTrait, BLOCK_SIZE};
pub const ALLOC_LIST_ENTRIES: usize = 255; pub const ALLOC_LIST_ENTRIES: usize =
(BLOCK_SIZE as usize - mem::size_of::<BlockPtr<AllocList>>()) / mem::size_of::<AllocEntry>();
/// The RedoxFS block allocator. This struct manages all "data" blocks in RedoxFS
/// (i.e, all blocks that aren't reserved or part of the header chain).
///
/// [`Allocator`] can allocate blocks of many "levels"---that is, it can
/// allocate multiple consecutive [`BLOCK_SIZE`] blocks in one operation.
///
/// This reduces the amount of memory that the [`Allocator`] uses:
/// Instead of storing the index of each free [`BLOCK_SIZE`] block,
/// the `levels` array can keep track of higher-level blocks, splitting
/// them when a smaller block is requested.
///
/// Higher-level blocks also allow us to more efficiently allocate memory
/// for large files.
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Allocator { pub struct Allocator {
/// This array keeps track of all free blocks of each level,
/// and is initialized using the AllocList chain when we open the filesystem.
///
/// Every element of the outer array represents a block level:
/// - item 0: free level 0 blocks (with size [`BLOCK_SIZE`])
/// - item 1: free level 1 blocks (with size 2*[`BLOCK_SIZE`])
/// - item 2: free level 2 blocks (with size 4*[`BLOCK_SIZE`])
/// ...and so on.
///
/// Each inner array contains a list of free block indices,
levels: Vec<Vec<u64>>, levels: Vec<Vec<u64>>,
} }
...@@ -16,6 +40,7 @@ impl Allocator { ...@@ -16,6 +40,7 @@ impl Allocator {
&self.levels &self.levels
} }
/// Count the number of free [`BLOCK_SIZE`] available to this [`Allocator`].
pub fn free(&self) -> u64 { pub fn free(&self) -> u64 {
let mut free = 0; let mut free = 0;
for level in 0..self.levels.len() { for level in 0..self.levels.len() {
...@@ -25,63 +50,79 @@ impl Allocator { ...@@ -25,63 +50,79 @@ impl Allocator {
free free
} }
pub fn allocate(&mut self) -> Option<u64> { /// Find a free block of the given level, mark it as "used", and return its address.
/// Returns [`None`] if there are no free blocks with this level.
pub fn allocate(&mut self, block_level: BlockLevel) -> Option<BlockAddr> {
// First, find the lowest level with a free block // First, find the lowest level with a free block
let mut addr_opt = None; let mut index_opt = None;
let mut level = 0; let mut level = block_level.0;
// Start searching at the level we want. Smaller levels are too small!
while level < self.levels.len() { while level < self.levels.len() {
if !self.levels[level].is_empty() { if !self.levels[level].is_empty() {
addr_opt = self.levels[level].pop(); index_opt = self.levels[level].pop();
break; break;
} }
level += 1; level += 1;
} }
// Next, if a free block was found, split it up until you have a usable level 0 block // If a free block was found, split it until we find a usable block of the right level.
let addr = addr_opt?; // The left side of the split block is kept free, and the right side is allocated.
while level > 0 { let index = index_opt?;
while level > block_level.0 {
level -= 1; level -= 1;
let level_size = 1 << level; let level_size = 1 << level;
self.levels[level].push(addr + level_size); self.levels[level].push(index + level_size);
} }
Some(addr) Some(unsafe { BlockAddr::new(index, block_level) })
} }
pub fn allocate_exact(&mut self, exact_addr: u64) -> Option<u64> { /// Try to allocate the exact block specified, making all necessary splits.
let mut addr_opt = None; /// Returns [`None`] if this some (or all) of this block is already allocated.
///
/// Note that [`BlockAddr`] encodes the blocks location _and_ level.
pub fn allocate_exact(&mut self, exact_addr: BlockAddr) -> Option<BlockAddr> {
// This function only supports level 0 right now
assert_eq!(exact_addr.level().0, 0);
let exact_index = exact_addr.index();
let mut index_opt = None;
// Go from the highest to the lowest level // Go from the highest to the lowest level
for level in (0..self.levels.len()).rev() { for level in (0..self.levels.len()).rev() {
let level_size = 1 << level; let level_size = 1 << level;
// Split higher block if found // Split higher block if found
if let Some(addr) = addr_opt.take() { if let Some(index) = index_opt.take() {
self.levels[level].push(addr); self.levels[level].push(index);
self.levels[level].push(addr + level_size); self.levels[level].push(index + level_size);
} }
// Look for matching block and remove it // Look for matching block and remove it
for i in 0..self.levels[level].len() { for i in 0..self.levels[level].len() {
let start = self.levels[level][i]; let start = self.levels[level][i];
if start <= exact_addr { if start <= exact_index {
let end = start + level_size; let end = start + level_size;
if end > exact_addr { if end > exact_index {
self.levels[level].remove(i); self.levels[level].remove(i);
addr_opt = Some(start); index_opt = Some(start);
break; break;
} }
} }
} }
} }
addr_opt Some(unsafe { BlockAddr::new(index_opt?, exact_addr.level()) })
} }
pub fn deallocate(&mut self, mut addr: u64) { /// Deallocate the given block, marking it "free" so that it can be re-used later.
// See if block matches with a sibling - if so, join them into a larger block, and populate pub fn deallocate(&mut self, addr: BlockAddr) {
// this all the way to the top level // When we deallocate, we check if block we're deallocating has a free sibling.
let mut level = 0; // If it does, we join the two to create one free block in the next (higher) level.
//
// We repeat this until we no longer have a sibling to join.
let mut index = addr.index();
let mut level = addr.level().0;
loop { loop {
while level >= self.levels.len() { while level >= self.levels.len() {
self.levels.push(Vec::new()); self.levels.push(Vec::new());
...@@ -92,51 +133,76 @@ impl Allocator { ...@@ -92,51 +133,76 @@ impl Allocator {
let mut found = false; let mut found = false;
let mut i = 0; let mut i = 0;
// look at all free blocks in the current level...
while i < self.levels[level].len() { while i < self.levels[level].len() {
let level_addr = self.levels[level][i]; // index of the second block we're looking at
if addr % next_size == 0 && addr + level_size == level_addr { let level_index = self.levels[level][i];
// - the block we just freed aligns with the next largest block, and
// - the second block we're looking at is the right sibling of this block
if index % next_size == 0 && index + level_size == level_index {
// "alloc" the next highest block, repeat deallocation process.
self.levels[level].remove(i); self.levels[level].remove(i);
found = true; found = true;
break; break;
} else if level_addr % next_size == 0 && level_addr + level_size == addr { // - the index of this block doesn't align with the next largest block, and
// - the block we're looking at is the left neighbor of this block
} else if level_index % next_size == 0 && level_index + level_size == index {
// "alloc" the next highest block, repeat deallocation process.
self.levels[level].remove(i); self.levels[level].remove(i);
addr = level_addr; index = level_index; // index moves to left block
found = true; found = true;
break; break;
} }
i += 1; i += 1;
} }
// We couldn't find a higher block,
// deallocate this one and finish
if !found { if !found {
self.levels[level].push(addr); self.levels[level].push(index);
return; return;
} }
// repeat deallocation process on the
// higher-level block we just created.
level += 1; level += 1;
} }
} }
} }
#[repr(packed)] #[repr(C, packed)]
pub struct AllocEntry { pub struct AllocEntry {
addr: u64le, /// The index of the first block this [`AllocEntry`] refers to
count: i64le, index: Le<u64>,
/// The number of blocks after (and including) `index` that are are free or used.
/// If negative, they are used; if positive, they are free.
count: Le<i64>,
} }
impl AllocEntry { impl AllocEntry {
pub fn new(addr: u64, count: i64) -> Self { pub fn new(index: u64, count: i64) -> Self {
Self { Self {
addr: addr.into(), index: index.into(),
count: count.into(), count: count.into(),
} }
} }
pub fn addr(&self) -> u64 { pub fn allocate(addr: BlockAddr) -> Self {
{ self.addr }.to_native() Self::new(addr.index(), -addr.level().blocks())
}
pub fn deallocate(addr: BlockAddr) -> Self {
Self::new(addr.index(), addr.level().blocks())
}
pub fn index(&self) -> u64 {
self.index.to_ne()
} }
pub fn count(&self) -> i64 { pub fn count(&self) -> i64 {
{ self.count }.to_native() self.count.to_ne()
} }
pub fn is_null(&self) -> bool { pub fn is_null(&self) -> bool {
...@@ -146,10 +212,7 @@ impl AllocEntry { ...@@ -146,10 +212,7 @@ impl AllocEntry {
impl Clone for AllocEntry { impl Clone for AllocEntry {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { *self
addr: self.addr,
count: self.count,
}
} }
} }
...@@ -158,7 +221,7 @@ impl Copy for AllocEntry {} ...@@ -158,7 +221,7 @@ impl Copy for AllocEntry {}
impl Default for AllocEntry { impl Default for AllocEntry {
fn default() -> Self { fn default() -> Self {
Self { Self {
addr: 0.into(), index: 0.into(),
count: 0.into(), count: 0.into(),
} }
} }
...@@ -166,27 +229,35 @@ impl Default for AllocEntry { ...@@ -166,27 +229,35 @@ impl Default for AllocEntry {
impl fmt::Debug for AllocEntry { impl fmt::Debug for AllocEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr = self.addr(); let index = self.index();
let count = self.count(); let count = self.count();
f.debug_struct("AllocEntry") f.debug_struct("AllocEntry")
.field("addr", &addr) .field("index", &index)
.field("count", &count) .field("count", &count)
.finish() .finish()
} }
} }
/// Alloc log node /// A node in the allocation chain.
#[repr(packed)] #[repr(C, packed)]
pub struct AllocList { pub struct AllocList {
/// A pointer to the previous AllocList.
/// If this is the null pointer, this is the first element of the chain.
pub prev: BlockPtr<AllocList>, pub prev: BlockPtr<AllocList>,
/// Allocation entries.
pub entries: [AllocEntry; ALLOC_LIST_ENTRIES], pub entries: [AllocEntry; ALLOC_LIST_ENTRIES],
} }
impl Default for AllocList { unsafe impl BlockTrait for AllocList {
fn default() -> Self { fn empty(level: BlockLevel) -> Option<Self> {
Self { if level.0 == 0 {
prev: BlockPtr::default(), Some(Self {
entries: [AllocEntry::default(); ALLOC_LIST_ENTRIES], prev: BlockPtr::default(),
entries: [AllocEntry::default(); ALLOC_LIST_ENTRIES],
})
} else {
None
} }
} }
} }
...@@ -238,14 +309,17 @@ fn alloc_node_size_test() { ...@@ -238,14 +309,17 @@ fn alloc_node_size_test() {
fn allocator_test() { fn allocator_test() {
let mut alloc = Allocator::default(); let mut alloc = Allocator::default();
assert_eq!(alloc.allocate(), None); assert_eq!(alloc.allocate(BlockLevel::default()), None);
alloc.deallocate(1); alloc.deallocate(unsafe { BlockAddr::new(1, BlockLevel::default()) });
assert_eq!(alloc.allocate(), Some(1)); assert_eq!(
assert_eq!(alloc.allocate(), None); alloc.allocate(BlockLevel::default()),
Some(unsafe { BlockAddr::new(1, BlockLevel::default()) })
);
assert_eq!(alloc.allocate(BlockLevel::default()), None);
for addr in 1023..2048 { for addr in 1023..2048 {
alloc.deallocate(addr); alloc.deallocate(unsafe { BlockAddr::new(addr, BlockLevel::default()) });
} }
assert_eq!(alloc.levels.len(), 11); assert_eq!(alloc.levels.len(), 11);
...@@ -260,9 +334,12 @@ fn allocator_test() { ...@@ -260,9 +334,12 @@ fn allocator_test() {
} }
for addr in 1023..2048 { for addr in 1023..2048 {
assert_eq!(alloc.allocate(), Some(addr)); assert_eq!(
alloc.allocate(BlockLevel::default()),
Some(unsafe { BlockAddr::new(addr, BlockLevel::default()) })
);
} }
assert_eq!(alloc.allocate(), None); assert_eq!(alloc.allocate(BlockLevel::default()), None);
assert_eq!(alloc.levels.len(), 11); assert_eq!(alloc.levels.len(), 11);
for level in 0..alloc.levels.len() { for level in 0..alloc.levels.len() {
......
...@@ -88,7 +88,7 @@ fn main() { ...@@ -88,7 +88,7 @@ fn main() {
process::exit(1); process::exit(1);
} }
let uuid = Uuid::from_bytes(&fs.header.uuid()).unwrap(); let uuid = Uuid::from_bytes(fs.header.uuid());
println!( println!(
"redoxfs-ar: created filesystem on {}, reserved {} blocks, size {} MB, uuid {}", "redoxfs-ar: created filesystem on {}, reserved {} blocks, size {} MB, uuid {}",
disk_path, disk_path,
......
...@@ -76,7 +76,7 @@ fn main() { ...@@ -76,7 +76,7 @@ fn main() {
let password = io::stdin() let password = io::stdin()
.read_passwd(&mut io::stderr()) .read_passwd(&mut io::stderr())
.unwrap() .unwrap()
.unwrap_or(String::new()); .unwrap_or_default();
eprintln!(); eprintln!();
...@@ -101,7 +101,7 @@ fn main() { ...@@ -101,7 +101,7 @@ fn main() {
ctime.subsec_nanos(), ctime.subsec_nanos(),
) { ) {
Ok(filesystem) => { Ok(filesystem) => {
let uuid = Uuid::from_bytes(&filesystem.header.uuid()).unwrap(); let uuid = Uuid::from_bytes(filesystem.header.uuid());
eprintln!( eprintln!(
"redoxfs-mkfs: created filesystem on {}, reserved {} blocks, size {} MB, uuid {}", "redoxfs-mkfs: created filesystem on {}, reserved {} blocks, size {} MB, uuid {}",
disk_path, disk_path,
......
#[cfg(not(target_os = "redox"))]
extern crate libc; extern crate libc;
extern crate redoxfs;
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
extern crate syscall; extern crate syscall;
extern crate redoxfs;
extern crate uuid; extern crate uuid;
use std::env; use std::env;
...@@ -13,13 +10,15 @@ use std::io::{self, Read, Write}; ...@@ -13,13 +10,15 @@ use std::io::{self, Read, Write};
use std::os::unix::io::{FromRawFd, RawFd}; use std::os::unix::io::{FromRawFd, RawFd};
use std::process; use std::process;
#[cfg(target_os = "redox")]
use std::{mem::MaybeUninit, ptr::addr_of_mut, sync::atomic::Ordering};
use redoxfs::{mount, DiskCache, DiskFile, FileSystem}; use redoxfs::{mount, DiskCache, DiskFile, FileSystem};
use termion::input::TermRead; use termion::input::TermRead;
use uuid::Uuid; use uuid::Uuid;
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
extern "C" fn unmount_handler(_s: usize) { extern "C" fn unmount_handler(_s: usize) {
use std::sync::atomic::Ordering;
redoxfs::IS_UMT.store(1, Ordering::SeqCst); redoxfs::IS_UMT.store(1, Ordering::SeqCst);
} }
...@@ -28,27 +27,32 @@ extern "C" fn unmount_handler(_s: usize) { ...@@ -28,27 +27,32 @@ extern "C" fn unmount_handler(_s: usize) {
//for, so I put 2. I don't think 0,0 is a valid sa_mask. I don't know what i'm doing here. When u //for, so I put 2. I don't think 0,0 is a valid sa_mask. I don't know what i'm doing here. When u
//send it a sigkill, it shuts off the filesystem //send it a sigkill, it shuts off the filesystem
fn setsig() { fn setsig() {
use syscall::{sigaction, SigAction, SigActionFlags, SIGTERM}; // TODO: High-level wrapper like the nix crate?
unsafe {
let sig_action = SigAction { let mut action = MaybeUninit::<libc::sigaction>::uninit();
sa_handler: Some(unmount_handler),
sa_mask: [0, 0], assert_eq!(
sa_flags: SigActionFlags::empty(), libc::sigemptyset(addr_of_mut!((*action.as_mut_ptr()).sa_mask)),
}; 0
);
sigaction(SIGTERM, Some(&sig_action), None).unwrap(); addr_of_mut!((*action.as_mut_ptr()).sa_flags).write(0);
addr_of_mut!((*action.as_mut_ptr()).sa_sigaction).write(unmount_handler as usize);
assert_eq!(
libc::sigaction(libc::SIGTERM, action.as_ptr(), core::ptr::null_mut()),
0
);
}
} }
#[cfg(not(target_os = "redox"))] #[cfg(not(target_os = "redox"))]
// on linux, this is implemented properly, so no need for this unscrupulous nonsense! // on linux, this is implemented properly, so no need for this unscrupulous nonsense!
fn setsig() {} fn setsig() {}
#[cfg(not(target_os = "redox"))]
fn fork() -> isize { fn fork() -> isize {
unsafe { libc::fork() as isize } unsafe { libc::fork() as isize }
} }
#[cfg(not(target_os = "redox"))]
fn pipe(pipes: &mut [i32; 2]) -> isize { fn pipe(pipes: &mut [i32; 2]) -> isize {
unsafe { libc::pipe(pipes.as_mut_ptr()) as isize } unsafe { libc::pipe(pipes.as_mut_ptr()) as isize }
} }
...@@ -61,23 +65,15 @@ fn bootloader_password() -> Option<Vec<u8>> { ...@@ -61,23 +65,15 @@ fn bootloader_password() -> Option<Vec<u8>> {
None None
} }
#[cfg(target_os = "redox")]
fn fork() -> isize {
unsafe { libc::fork() as isize }
}
#[cfg(target_os = "redox")]
fn pipe(pipes: &mut [usize; 2]) -> isize {
syscall::Error::mux(syscall::pipe2(pipes, 0)) as isize
}
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
fn capability_mode() { fn capability_mode() {
syscall::setrens(0, 0).expect("redoxfs: failed to enter null namespace"); libredox::call::setrens(0, 0).expect("redoxfs: failed to enter null namespace");
} }
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
fn bootloader_password() -> Option<Vec<u8>> { fn bootloader_password() -> Option<Vec<u8>> {
use libredox::call::MmapArgs;
let addr_env = env::var_os("REDOXFS_PASSWORD_ADDR")?; let addr_env = env::var_os("REDOXFS_PASSWORD_ADDR")?;
let size_env = env::var_os("REDOXFS_PASSWORD_SIZE")?; let size_env = env::var_os("REDOXFS_PASSWORD_SIZE")?;
...@@ -95,20 +91,44 @@ fn bootloader_password() -> Option<Vec<u8>> { ...@@ -95,20 +91,44 @@ fn bootloader_password() -> Option<Vec<u8>> {
let mut password = Vec::with_capacity(size); let mut password = Vec::with_capacity(size);
unsafe { unsafe {
let password_map = syscall::physmap(addr, size, syscall::PhysmapFlags::empty()) let aligned_size = size.next_multiple_of(syscall::PAGE_SIZE);
.expect("failed to map REDOXFS_PASSWORD");
let fd = libredox::Fd::open("memory:physical", libredox::flag::O_CLOEXEC, 0)
.expect("failed to open physical memory file");
let password_map = libredox::call::mmap(MmapArgs {
addr: core::ptr::null_mut(),
length: aligned_size,
prot: libredox::flag::PROT_READ,
flags: libredox::flag::MAP_SHARED,
fd: fd.raw(),
offset: addr as u64,
})
.expect("failed to map REDOXFS_PASSWORD")
.cast::<u8>();
for i in 0..size { for i in 0..size {
password.push(*((password_map + i) as *const u8)); password.push(password_map.add(i).read());
} }
let _ = syscall::physunmap(password_map); let _ = libredox::call::munmap(password_map.cast(), aligned_size);
} }
Some(password) Some(password)
} }
fn print_err_exit(err: impl AsRef<str>) -> ! {
eprintln!("{}", err.as_ref());
usage();
process::exit(1)
}
fn print_usage_exit() -> ! {
usage();
process::exit(1)
}
fn usage() { fn usage() {
println!("redoxfs [--uuid] [disk or uuid] [mountpoint] [block in hex]"); println!("redoxfs --no-daemon [-d] [--uuid] [disk or uuid] [mountpoint] [block in hex]");
} }
enum DiskId { enum DiskId {
...@@ -129,7 +149,7 @@ fn filesystem_by_path( ...@@ -129,7 +149,7 @@ fn filesystem_by_path(
let password = io::stdin() let password = io::stdin()
.read_passwd(&mut io::stderr()) .read_passwd(&mut io::stderr())
.unwrap() .unwrap()
.unwrap_or(String::new()); .unwrap_or_default();
eprintln!(); eprintln!();
...@@ -145,36 +165,31 @@ fn filesystem_by_path( ...@@ -145,36 +165,31 @@ fn filesystem_by_path(
bootloader_password() bootloader_password()
}; };
match DiskFile::open(&path).map(|image| DiskCache::new(image)) { match DiskFile::open(path).map(DiskCache::new) {
Ok(disk) => match redoxfs::FileSystem::open( Ok(disk) => {
disk, match redoxfs::FileSystem::open(disk, password_opt.as_deref(), block_opt, true) {
password_opt.as_ref().map(|x| x.as_slice()), Ok(filesystem) => {
block_opt, println!(
true, "redoxfs: opened filesystem on {} with uuid {}",
) { path,
Ok(filesystem) => { Uuid::from_bytes(filesystem.header.uuid()).hyphenated()
println!( );
"redoxfs: opened filesystem on {} with uuid {}",
path, return Some((path.to_string(), filesystem));
Uuid::from_bytes(&filesystem.header.uuid())
.unwrap()
.hyphenated()
);
return Some((path.to_string(), filesystem));
}
Err(err) => match err.errno {
syscall::ENOKEY => {
if password_opt.is_some() {
println!("redoxfs: incorrect password ({}/{})", attempt, attempts);
}
}
_ => {
println!("redoxfs: failed to open filesystem {}: {}", path, err);
break;
} }
}, Err(err) => match err.errno {
}, syscall::ENOKEY => {
if password_opt.is_some() {
println!("redoxfs: incorrect password ({}/{})", attempt, attempts);
}
}
_ => {
println!("redoxfs: failed to open filesystem {}: {}", path, err);
break;
}
},
}
}
Err(err) => { Err(err) => {
println!("redoxfs: failed to open image {}: {}", path, err); println!("redoxfs: failed to open image {}: {}", path, err);
break; break;
...@@ -199,15 +214,19 @@ fn filesystem_by_uuid( ...@@ -199,15 +214,19 @@ fn filesystem_by_uuid(
) -> Option<(String, FileSystem<DiskCache<DiskFile>>)> { ) -> Option<(String, FileSystem<DiskCache<DiskFile>>)> {
use std::fs; use std::fs;
match fs::read_dir(":") { use redox_path::RedoxPath;
match fs::read_dir("/scheme") {
Ok(entries) => { Ok(entries) => {
for entry_res in entries { for entry_res in entries {
if let Ok(entry) = entry_res { if let Ok(entry) = entry_res {
if let Ok(path) = entry.path().into_os_string().into_string() { if let Some(disk) = entry.path().to_str() {
let scheme = path.trim_start_matches(':').trim_matches('/'); if RedoxPath::from_absolute(disk)
if scheme.starts_with("disk") { .unwrap_or(RedoxPath::from_absolute("/")?)
println!("redoxfs: found scheme {}", scheme); .is_scheme_category("disk")
match fs::read_dir(&format!("{}:", scheme)) { {
println!("redoxfs: found scheme {}", disk);
match fs::read_dir(disk) {
Ok(entries) => { Ok(entries) => {
for entry_res in entries { for entry_res in entries {
if let Ok(entry) = entry_res { if let Ok(entry) = entry_res {
...@@ -239,7 +258,7 @@ fn filesystem_by_uuid( ...@@ -239,7 +258,7 @@ fn filesystem_by_uuid(
} }
} }
Err(err) => { Err(err) => {
println!("redoxfs: failed to list '{}': {}", scheme, err); println!("redoxfs: failed to list '{}': {}", disk, err);
} }
} }
} }
...@@ -255,7 +274,12 @@ fn filesystem_by_uuid( ...@@ -255,7 +274,12 @@ fn filesystem_by_uuid(
None None
} }
fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write: File) -> ! { fn daemon(
disk_id: &DiskId,
mountpoint: &str,
block_opt: Option<u64>,
mut write: Option<File>,
) -> ! {
setsig(); setsig();
let filesystem_opt = match *disk_id { let filesystem_opt = match *disk_id {
...@@ -264,7 +288,7 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write: ...@@ -264,7 +288,7 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write:
}; };
if let Some((path, filesystem)) = filesystem_opt { if let Some((path, filesystem)) = filesystem_opt {
match mount(filesystem, &mountpoint, |mounted_path| { match mount(filesystem, mountpoint, |mounted_path| {
capability_mode(); capability_mode();
println!( println!(
...@@ -272,7 +296,10 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write: ...@@ -272,7 +296,10 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write:
path, path,
mounted_path.display() mounted_path.display()
); );
let _ = write.write(&[0]);
if let Some(ref mut write) = write {
let _ = write.write(&[0]);
}
}) { }) {
Ok(()) => { Ok(()) => {
process::exit(0); process::exit(0);
...@@ -295,7 +322,10 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write: ...@@ -295,7 +322,10 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write:
} }
} }
let _ = write.write(&[1]); if let Some(ref mut write) = write {
let _ = write.write(&[1]);
}
process::exit(1); process::exit(1);
} }
...@@ -304,79 +334,74 @@ fn main() { ...@@ -304,79 +334,74 @@ fn main() {
let mut args = env::args().skip(1); let mut args = env::args().skip(1);
let disk_id = match args.next() { let mut daemonise = true;
Some(arg) => { let mut disk_id: Option<DiskId> = None;
if arg == "--uuid" { let mut mountpoint: Option<String> = None;
let uuid = match args.next() { let mut block_opt: Option<u64> = None;
Some(arg) => match Uuid::parse_str(&arg) {
Ok(uuid) => uuid, while let Some(arg) = args.next() {
Err(err) => { match arg.as_str() {
println!("redoxfs: invalid uuid '{}': {}", arg, err); "--no-daemon" | "-d" => daemonise = false,
usage();
process::exit(1); "--uuid" if disk_id.is_none() => {
disk_id = Some(DiskId::Uuid(
match args.next().as_deref().map(Uuid::parse_str) {
Some(Ok(uuid)) => uuid,
Some(Err(err)) => {
print_err_exit(format!("redoxfs: invalid uuid '{}': {}", arg, err))
} }
None => print_err_exit("redoxfs: no uuid provided"),
}, },
None => { ));
println!("redoxfs: no uuid provided");
usage();
process::exit(1);
}
};
DiskId::Uuid(uuid)
} else {
DiskId::Path(arg)
} }
}
None => {
println!("redoxfs: no disk provided");
usage();
process::exit(1);
}
};
let mountpoint = match args.next() { disk if disk_id.is_none() => disk_id = Some(DiskId::Path(disk.to_owned())),
Some(arg) => arg,
None => { mnt if disk_id.is_some() && mountpoint.is_none() => mountpoint = Some(mnt.to_owned()),
println!("redoxfs: no mountpoint provided");
usage(); opts if mountpoint.is_some() => match u64::from_str_radix(opts, 16) {
process::exit(1); Ok(block) => block_opt = Some(block),
Err(err) => print_err_exit(format!("redoxfs: invalid block '{}': {}", opts, err)),
},
_ => print_usage_exit(),
} }
}
let Some(disk_id) = disk_id else {
print_err_exit("redoxfs: no disk provided");
}; };
let block_opt = match args.next() { let Some(mountpoint) = mountpoint else {
Some(arg) => match u64::from_str_radix(&arg, 16) { print_err_exit("redoxfs: no mountpoint provided");
Ok(block) => Some(block),
Err(err) => {
println!("redoxfs: invalid block '{}': {}", arg, err);
usage();
process::exit(1);
}
},
None => None,
}; };
let mut pipes = [0; 2]; if daemonise {
if pipe(&mut pipes) == 0 { let mut pipes = [0; 2];
let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; if pipe(&mut pipes) == 0 {
let write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) };
let write = unsafe { File::from_raw_fd(pipes[1] as RawFd) };
let pid = fork(); let pid = fork();
if pid == 0 { if pid == 0 {
drop(read); drop(read);
daemon(&disk_id, &mountpoint, block_opt, write); daemon(&disk_id, &mountpoint, block_opt, Some(write));
} else if pid > 0 { } else if pid > 0 {
drop(write); drop(write);
let mut res = [0]; let mut res = [0];
read.read_exact(&mut res).unwrap(); read.read_exact(&mut res).unwrap();
process::exit(res[0] as i32); process::exit(res[0] as i32);
} else {
panic!("redoxfs: failed to fork");
}
} else { } else {
panic!("redoxfs: failed to fork"); panic!("redoxfs: failed to create pipe");
} }
} else { } else {
panic!("redoxfs: failed to create pipe"); println!("redoxfs: running in foreground");
daemon(&disk_id, &mountpoint, block_opt, None);
} }
} }
use core::{fmt, marker::PhantomData, mem, ops, slice}; use core::{fmt, marker::PhantomData, mem, ops, slice};
use simple_endian::*; use endian_num::Le;
use crate::BLOCK_SIZE; use crate::BLOCK_SIZE;
const BLOCK_LIST_ENTRIES: usize = BLOCK_SIZE as usize / mem::size_of::<BlockPtr<BlockRaw>>();
/// An address of a data block.
///
/// This encodes a block's position _and_ [`BlockLevel`]:
/// the first four bits of this `u64` encode the block's level,
/// the rest encode its index.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BlockAddr(u64);
impl BlockAddr {
// Unsafe because this can create invalid blocks
pub(crate) unsafe fn new(index: u64, level: BlockLevel) -> Self {
// Level must only use the lowest four bits
if level.0 > 0xF {
panic!("block level used more than four bits");
}
// Index must not use the highest four bits
let inner = index
.checked_shl(4)
.expect("block index used highest four bits")
| (level.0 as u64);
Self(inner)
}
pub fn null(level: BlockLevel) -> Self {
unsafe { Self::new(0, level) }
}
pub fn index(&self) -> u64 {
// The first four bits store the level
self.0 >> 4
}
pub fn level(&self) -> BlockLevel {
// The first four bits store the level
BlockLevel((self.0 & 0xF) as usize)
}
pub fn is_null(&self) -> bool {
self.index() == 0
}
}
/// The size of a block.
///
/// Level 0 blocks are blocks of [`BLOCK_SIZE`] bytes.
/// A level 1 block consists of two consecutive level 0 blocks.
/// A level n block consists of two consecutive level n-1 blocks.
///
/// See [`crate::Allocator`] docs for more details.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BlockLevel(pub(crate) usize);
impl BlockLevel {
/// Returns the smallest block level that can contain
/// the given number of bytes.
pub(crate) fn for_bytes(bytes: u64) -> Self {
if bytes == 0 {
return BlockLevel(0);
}
let level = bytes
.div_ceil(BLOCK_SIZE)
.next_power_of_two()
.trailing_zeros() as usize;
BlockLevel(level)
}
/// The number of [`BLOCK_SIZE`] blocks (i.e, level 0 blocks)
/// in a block of this level
pub fn blocks(self) -> i64 {
1 << self.0
}
/// The number of bytes in a block of this level
pub fn bytes(self) -> u64 {
BLOCK_SIZE << self.0
}
}
pub unsafe trait BlockTrait {
/// Create an empty block of this type.
fn empty(level: BlockLevel) -> Option<Self>
where
Self: Sized;
}
/// A [`BlockAddr`] and the data it points to.
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct BlockData<T> { pub struct BlockData<T> {
addr: u64, addr: BlockAddr,
data: T, data: T,
} }
impl<T> BlockData<T> { impl<T> BlockData<T> {
pub fn new(addr: u64, data: T) -> Self { pub fn new(addr: BlockAddr, data: T) -> Self {
Self { addr, data } Self { addr, data }
} }
pub fn addr(&self) -> u64 { pub fn addr(&self) -> BlockAddr {
self.addr self.addr
} }
#[must_use = "don't forget to de-allocate old block address"]
pub fn swap_addr(&mut self, addr: u64) -> u64 {
let old = self.addr;
self.addr = addr;
old
}
pub fn data(&self) -> &T { pub fn data(&self) -> &T {
&self.data &self.data
} }
...@@ -33,24 +115,56 @@ impl<T> BlockData<T> { ...@@ -33,24 +115,56 @@ impl<T> BlockData<T> {
&mut self.data &mut self.data
} }
pub fn into_data(self) -> T { pub(crate) unsafe fn into_parts(self) -> (BlockAddr, T) {
self.data (self.addr, self.data)
}
/// Set the address of this [`BlockData`] to `addr`, returning this
/// block's old address. This method does not update block data.
///
/// `addr` must point to a block with the same level as this block.
#[must_use = "don't forget to de-allocate old block address"]
pub fn swap_addr(&mut self, addr: BlockAddr) -> BlockAddr {
// Address levels must match
assert_eq!(self.addr.level(), addr.level());
let old = self.addr;
self.addr = addr;
old
}
}
impl<T: BlockTrait> BlockData<T> {
pub fn empty(addr: BlockAddr) -> Option<Self> {
let empty = T::empty(addr.level())?;
Some(Self::new(addr, empty))
} }
} }
impl<T: ops::Deref<Target = [u8]>> BlockData<T> { impl<T: ops::Deref<Target = [u8]>> BlockData<T> {
pub fn create_ptr(&self) -> BlockPtr<T> { pub fn create_ptr(&self) -> BlockPtr<T> {
BlockPtr { BlockPtr {
addr: self.addr.into(), addr: self.addr.0.into(),
hash: seahash::hash(self.data.deref()).into(), hash: seahash::hash(self.data.deref()).into(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
} }
#[repr(packed)] #[repr(C, packed)]
pub struct BlockList<T> { pub struct BlockList<T> {
pub ptrs: [BlockPtr<T>; 256], pub ptrs: [BlockPtr<T>; BLOCK_LIST_ENTRIES],
}
unsafe impl<T> BlockTrait for BlockList<T> {
fn empty(level: BlockLevel) -> Option<Self> {
if level.0 == 0 {
Some(Self {
ptrs: [BlockPtr::default(); BLOCK_LIST_ENTRIES],
})
} else {
None
}
}
} }
impl<T> BlockList<T> { impl<T> BlockList<T> {
...@@ -64,14 +178,6 @@ impl<T> BlockList<T> { ...@@ -64,14 +178,6 @@ impl<T> BlockList<T> {
} }
} }
impl<T> Default for BlockList<T> {
fn default() -> Self {
Self {
ptrs: [BlockPtr::default(); 256],
}
}
}
impl<T> ops::Deref for BlockList<T> { impl<T> ops::Deref for BlockList<T> {
type Target = [u8]; type Target = [u8];
fn deref(&self) -> &[u8] { fn deref(&self) -> &[u8] {
...@@ -95,24 +201,39 @@ impl<T> ops::DerefMut for BlockList<T> { ...@@ -95,24 +201,39 @@ impl<T> ops::DerefMut for BlockList<T> {
} }
} }
#[repr(packed)] /// An address of a data block, along with a checksum of its data.
///
/// This encodes a block's position _and_ [`BlockLevel`].
/// the first four bits of `addr` encode the block's level,
/// the rest encode its index.
///
/// Also see [`BlockAddr`].
#[repr(C, packed)]
pub struct BlockPtr<T> { pub struct BlockPtr<T> {
addr: u64le, addr: Le<u64>,
hash: u64le, hash: Le<u64>,
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
impl<T> BlockPtr<T> { impl<T> BlockPtr<T> {
pub fn addr(&self) -> u64 { pub fn null(level: BlockLevel) -> Self {
{ self.addr }.to_native() Self {
addr: BlockAddr::null(level).0.into(),
hash: 0.into(),
phantom: PhantomData,
}
}
pub fn addr(&self) -> BlockAddr {
BlockAddr(self.addr.to_ne())
} }
pub fn hash(&self) -> u64 { pub fn hash(&self) -> u64 {
{ self.hash }.to_native() self.hash.to_ne()
} }
pub fn is_null(&self) -> bool { pub fn is_null(&self) -> bool {
self.addr() == 0 self.addr().is_null()
} }
/// Cast BlockPtr to another type /// Cast BlockPtr to another type
...@@ -137,11 +258,7 @@ impl<T> BlockPtr<T> { ...@@ -137,11 +258,7 @@ impl<T> BlockPtr<T> {
impl<T> Clone for BlockPtr<T> { impl<T> Clone for BlockPtr<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { *self
addr: self.addr,
hash: self.hash,
phantom: PhantomData,
}
} }
} }
...@@ -168,18 +285,22 @@ impl<T> fmt::Debug for BlockPtr<T> { ...@@ -168,18 +285,22 @@ impl<T> fmt::Debug for BlockPtr<T> {
} }
} }
#[repr(packed)] #[repr(C, packed)]
pub struct BlockRaw([u8; BLOCK_SIZE as usize]); pub struct BlockRaw([u8; BLOCK_SIZE as usize]);
impl Clone for BlockRaw { unsafe impl BlockTrait for BlockRaw {
fn clone(&self) -> Self { fn empty(level: BlockLevel) -> Option<Self> {
Self(self.0) if level.0 == 0 {
Some(Self([0; BLOCK_SIZE as usize]))
} else {
None
}
} }
} }
impl Default for BlockRaw { impl Clone for BlockRaw {
fn default() -> Self { fn clone(&self) -> Self {
Self([0; BLOCK_SIZE as usize]) Self(self.0)
} }
} }
......
use alloc::{boxed::Box, vec};
use core::{mem, ops, slice, str}; use core::{mem, ops, slice, str};
use crate::{Node, TreePtr}; use crate::{BlockLevel, BlockTrait, Node, TreePtr, DIR_ENTRY_MAX_LENGTH, RECORD_LEVEL};
#[repr(packed)] #[repr(C, packed)]
pub struct DirEntry { pub struct DirEntry {
node_ptr: TreePtr<Node>, node_ptr: TreePtr<Node>,
name: [u8; 252], name: [u8; DIR_ENTRY_MAX_LENGTH],
} }
impl DirEntry { impl DirEntry {
pub fn new(node_ptr: TreePtr<Node>, name: &str) -> Option<DirEntry> { pub fn new(node_ptr: TreePtr<Node>, name: &str) -> DirEntry {
let mut entry = DirEntry { let mut entry = DirEntry {
node_ptr, node_ptr,
..Default::default() ..Default::default()
}; };
if name.len() > entry.name.len() {
return None;
}
entry.name[..name.len()].copy_from_slice(name.as_bytes()); entry.name[..name.len()].copy_from_slice(name.as_bytes());
Some(entry) entry
} }
pub fn node_ptr(&self) -> TreePtr<Node> { pub fn node_ptr(&self) -> TreePtr<Node> {
...@@ -43,10 +40,7 @@ impl DirEntry { ...@@ -43,10 +40,7 @@ impl DirEntry {
impl Clone for DirEntry { impl Clone for DirEntry {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { *self
node_ptr: self.node_ptr,
name: self.name,
}
} }
} }
...@@ -56,14 +50,27 @@ impl Default for DirEntry { ...@@ -56,14 +50,27 @@ impl Default for DirEntry {
fn default() -> Self { fn default() -> Self {
Self { Self {
node_ptr: TreePtr::default(), node_ptr: TreePtr::default(),
name: [0; 252], name: [0; DIR_ENTRY_MAX_LENGTH],
} }
} }
} }
#[repr(packed)] //TODO: this is a box to prevent stack overflows
pub struct DirList { pub struct DirList {
pub entries: [DirEntry; 16], pub entries: Box<[DirEntry]>,
}
unsafe impl BlockTrait for DirList {
fn empty(level: BlockLevel) -> Option<Self> {
if level.0 <= RECORD_LEVEL {
let entries = level.bytes() as usize / mem::size_of::<DirEntry>();
Some(Self {
entries: vec![DirEntry::default(); entries].into_boxed_slice(),
})
} else {
None
}
}
} }
impl DirList { impl DirList {
...@@ -77,21 +84,13 @@ impl DirList { ...@@ -77,21 +84,13 @@ impl DirList {
} }
} }
impl Default for DirList {
fn default() -> Self {
Self {
entries: [DirEntry::default(); 16],
}
}
}
impl ops::Deref for DirList { impl ops::Deref for DirList {
type Target = [u8]; type Target = [u8];
fn deref(&self) -> &[u8] { fn deref(&self) -> &[u8] {
unsafe { unsafe {
slice::from_raw_parts( slice::from_raw_parts(
self as *const DirList as *const u8, self.entries.as_ptr() as *const u8,
mem::size_of::<DirList>(), self.entries.len() * mem::size_of::<DirEntry>(),
) as &[u8] ) as &[u8]
} }
} }
...@@ -100,13 +99,22 @@ impl ops::Deref for DirList { ...@@ -100,13 +99,22 @@ impl ops::Deref for DirList {
impl ops::DerefMut for DirList { impl ops::DerefMut for DirList {
fn deref_mut(&mut self) -> &mut [u8] { fn deref_mut(&mut self) -> &mut [u8] {
unsafe { unsafe {
slice::from_raw_parts_mut(self as *mut DirList as *mut u8, mem::size_of::<DirList>()) slice::from_raw_parts_mut(
as &mut [u8] self.entries.as_mut_ptr() as *mut u8,
self.entries.len() * mem::size_of::<DirEntry>(),
) as &mut [u8]
} }
} }
} }
#[test] #[test]
fn dir_list_size_test() { fn dir_list_size_test() {
assert_eq!(mem::size_of::<DirList>(), crate::BLOCK_SIZE as usize); use core::ops::Deref;
for level_i in 0..RECORD_LEVEL {
let level = BlockLevel(level_i);
assert_eq!(
DirList::empty(level).unwrap().deref().len(),
level.bytes() as usize
);
}
} }
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Seek, SeekFrom};
use std::os::unix::fs::FileExt;
use std::path::Path; use std::path::Path;
use syscall::error::{Error, Result, EIO}; use syscall::error::{Error, Result, EIO};
use crate::disk::Disk; use crate::disk::Disk;
use crate::BLOCK_SIZE; use crate::BLOCK_SIZE;
macro_rules! try_disk { pub struct DiskFile {
($expr:expr) => { pub file: File,
match $expr { }
Ok(val) => val,
trait ResultExt {
type T;
fn or_eio(self) -> Result<Self::T>;
}
impl<T> ResultExt for Result<T> {
type T = T;
fn or_eio(self) -> Result<Self::T> {
match self {
Ok(t) => Ok(t),
Err(err) => { Err(err) => {
eprintln!("Disk I/O Error: {}", err); eprintln!("RedoxFS: IO ERROR: {err}");
return Err(Error::new(EIO)); Err(Error::new(EIO))
} }
} }
}; }
} }
impl<T> ResultExt for std::io::Result<T> {
pub struct DiskFile { type T = T;
pub file: File, fn or_eio(self) -> Result<Self::T> {
match self {
Ok(t) => Ok(t),
Err(err) => {
eprintln!("RedoxFS: IO ERROR: {err}");
Err(Error::new(EIO))
}
}
}
} }
impl DiskFile { impl DiskFile {
pub fn open<P: AsRef<Path>>(path: P) -> Result<DiskFile> { pub fn open(path: impl AsRef<Path>) -> Result<DiskFile> {
let file = try_disk!(OpenOptions::new().read(true).write(true).open(path)); let file = OpenOptions::new()
.read(true)
.write(true)
.open(path)
.or_eio()?;
Ok(DiskFile { file }) Ok(DiskFile { file })
} }
pub fn create<P: AsRef<Path>>(path: P, size: u64) -> Result<DiskFile> { pub fn create(path: impl AsRef<Path>, size: u64) -> Result<DiskFile> {
let file = try_disk!(OpenOptions::new() let file = OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
.create(true) .create(true)
.open(path)); .open(path)
try_disk!(file.set_len(size)); .or_eio()?;
file.set_len(size).or_eio()?;
Ok(DiskFile { file }) Ok(DiskFile { file })
} }
} }
impl Disk for DiskFile { impl Disk for DiskFile {
unsafe fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> { unsafe fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
try_disk!(self.file.seek(SeekFrom::Start(block * BLOCK_SIZE))); self.file.read_at(buffer, block * BLOCK_SIZE).or_eio()
let count = try_disk!(self.file.read(buffer));
Ok(count)
} }
unsafe fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize> { unsafe fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
try_disk!(self.file.seek(SeekFrom::Start(block * BLOCK_SIZE))); self.file.write_at(buffer, block * BLOCK_SIZE).or_eio()
let count = try_disk!(self.file.write(buffer));
Ok(count)
} }
fn size(&mut self) -> Result<u64> { fn size(&mut self) -> Result<u64> {
let size = try_disk!(self.file.seek(SeekFrom::End(0))); self.file.seek(SeekFrom::End(0)).or_eio()
Ok(size)
} }
} }
use core::cmp::min;
use BLOCK_SIZE;
pub struct BlockIter {
block: u64,
length: u64,
i: u64,
}
impl Iterator for BlockIter {
type Item = (u64, u64);
fn next(&mut self) -> Option<Self::Item> {
if self.i < (self.length + BLOCK_SIZE - 1) / BLOCK_SIZE {
let ret = Some((
self.block + self.i,
min(BLOCK_SIZE, self.length - self.i * BLOCK_SIZE),
));
self.i += 1;
ret
} else {
None
}
}
}
/// A disk extent, [wikipedia](https://en.wikipedia.org/wiki/Extent_(file_systems))
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct Extent {
pub block: u64,
pub length: u64,
}
impl Extent {
pub fn default() -> Extent {
Extent {
block: 0,
length: 0,
}
}
pub fn new(block: u64, length: u64) -> Extent {
Extent {
block: block,
length: length,
}
}
pub fn blocks(&self) -> BlockIter {
BlockIter {
block: self.block,
length: self.length,
i: 0,
}
}
}
use aes::{Aes128, BlockDecrypt, BlockEncrypt}; use aes::{Aes128, BlockDecrypt, BlockEncrypt};
use alloc::{collections::VecDeque, vec::Vec}; use alloc::{collections::VecDeque, vec::Vec};
use core::mem; use syscall::error::{Error, Result, EKEYREJECTED, ENOENT, ENOKEY};
use syscall::error::{Error, Result, EKEYREJECTED, EIO, ENOENT, ENOKEY, ENOSPC};
use crate::{ #[cfg(feature = "std")]
AllocEntry, AllocList, Allocator, BlockData, Disk, Header, Key, KeySlot, Node, Salt, use crate::{AllocEntry, AllocList, BlockData, BlockTrait, Key, KeySlot, Node, Salt, TreeList};
Transaction, TreeList, BLOCK_SIZE, HEADER_RING, use crate::{Allocator, BlockAddr, BlockLevel, Disk, Header, Transaction, BLOCK_SIZE, HEADER_RING};
};
/// A file system /// A file system
pub struct FileSystem<D: Disk> { pub struct FileSystem<D: Disk> {
...@@ -122,93 +120,99 @@ impl<D: Disk> FileSystem<D> { ...@@ -122,93 +120,99 @@ impl<D: Disk> FileSystem<D> {
let size = disk.size()?; let size = disk.size()?;
let block_offset = (reserved.len() as u64 + BLOCK_SIZE - 1) / BLOCK_SIZE; let block_offset = (reserved.len() as u64 + BLOCK_SIZE - 1) / BLOCK_SIZE;
if size >= (block_offset + HEADER_RING + 4) * BLOCK_SIZE { if size < (block_offset + HEADER_RING + 4) * BLOCK_SIZE {
for block in 0..block_offset as usize { return Err(Error::new(syscall::error::ENOSPC));
let mut data = [0; BLOCK_SIZE as usize]; }
let mut i = 0; // Fill reserved data, pad with zeroes
while i < data.len() && block * BLOCK_SIZE as usize + i < reserved.len() { for block in 0..block_offset as usize {
data[i] = reserved[block * BLOCK_SIZE as usize + i]; let mut data = [0; BLOCK_SIZE as usize];
i += 1;
}
unsafe { let mut i = 0;
disk.write_at(block as u64, &data)?; while i < data.len() && block * BLOCK_SIZE as usize + i < reserved.len() {
} data[i] = reserved[block * BLOCK_SIZE as usize + i];
i += 1;
} }
let mut header = Header::new(size); unsafe {
disk.write_at(block as u64, &data)?;
let aes_opt = match password_opt { }
Some(password) => { }
//TODO: handle errors
header.key_slots[0] =
KeySlot::new(password, Salt::new().unwrap(), Key::new().unwrap()).unwrap();
Some(header.key_slots[0].key(password).unwrap().into_aes())
}
None => None,
};
let mut fs = FileSystem { let mut header = Header::new(size);
disk,
block: block_offset,
header,
allocator: Allocator::default(),
aes_opt,
aes_blocks: Vec::with_capacity(BLOCK_SIZE as usize / aes::BLOCK_SIZE),
};
// Write header generation zero let aes_opt = match password_opt {
let count = unsafe { Some(password) => {
fs.disk.write_at(fs.block, &fs.header)? //TODO: handle errors
}; header.key_slots[0] =
if count != mem::size_of_val(&fs.header) { KeySlot::new(password, Salt::new().unwrap(), Key::new().unwrap()).unwrap();
// Wrote wrong number of bytes Some(header.key_slots[0].key(password).unwrap().into_aes())
#[cfg(feature = "log")]
log::error!("CREATE: WRONG NUMBER OF BYTES");
return Err(Error::new(EIO));
} }
None => None,
};
let mut fs = FileSystem {
disk,
block: block_offset,
header,
allocator: Allocator::default(),
aes_opt,
aes_blocks: Vec::with_capacity(BLOCK_SIZE as usize / aes::BLOCK_SIZE),
};
// Write header generation zero
let count = unsafe { fs.disk.write_at(fs.block, &fs.header)? };
if count != core::mem::size_of_val(&fs.header) {
// Wrote wrong number of bytes
#[cfg(feature = "log")]
log::error!("CREATE: WRONG NUMBER OF BYTES");
return Err(Error::new(syscall::error::EIO));
}
// Set tree and alloc pointers and write header generation one // Set tree and alloc pointers and write header generation one
fs.tx(|tx| unsafe { fs.tx(|tx| unsafe {
let tree = BlockData::new(HEADER_RING + 1, TreeList::default()); let tree = BlockData::new(
BlockAddr::new(HEADER_RING + 1, BlockLevel::default()),
TreeList::empty(BlockLevel::default()).unwrap(),
);
let mut alloc = BlockData::new(HEADER_RING + 2, AllocList::default()); let mut alloc = BlockData::new(
let alloc_free = size / BLOCK_SIZE - (block_offset + HEADER_RING + 4); BlockAddr::new(HEADER_RING + 2, BlockLevel::default()),
alloc.data_mut().entries[0] = AllocEntry::new(HEADER_RING + 4, alloc_free as i64); AllocList::empty(BlockLevel::default()).unwrap(),
);
tx.header.tree = tx.write_block(tree)?; let alloc_free = size / BLOCK_SIZE - (block_offset + HEADER_RING + 4);
tx.header.alloc = tx.write_block(alloc)?; alloc.data_mut().entries[0] = AllocEntry::new(HEADER_RING + 4, alloc_free as i64);
tx.header_changed = true;
Ok(()) tx.header.tree = tx.write_block(tree)?;
})?; tx.header.alloc = tx.write_block(alloc)?;
tx.header_changed = true;
unsafe { Ok(())
fs.reset_allocator()?; })?;
}
fs.tx(|tx| unsafe { unsafe {
let mut root = BlockData::new( fs.reset_allocator()?;
HEADER_RING + 3,
Node::new(Node::MODE_DIR | 0o755, 0, 0, ctime, ctime_nsec),
);
root.data_mut().set_links(1);
let root_ptr = tx.write_block(root)?;
assert_eq!(tx.insert_tree(root_ptr)?.id(), 1);
Ok(())
})?;
// Make sure everything is synced and squash allocations
Transaction::new(&mut fs).commit(true)?;
Ok(fs)
} else {
Err(Error::new(ENOSPC))
} }
fs.tx(|tx| unsafe {
let mut root = BlockData::new(
BlockAddr::new(HEADER_RING + 3, BlockLevel::default()),
Node::new(Node::MODE_DIR | 0o755, 0, 0, ctime, ctime_nsec),
);
root.data_mut().set_links(1);
let root_ptr = tx.write_block(root)?;
assert_eq!(tx.insert_tree(root_ptr)?.id(), 1);
Ok(())
})?;
// Make sure everything is synced and squash allocations
Transaction::new(&mut fs).commit(true)?;
Ok(fs)
} }
/// Start a filesystem transaction, required for making any changes /// start a filesystem transaction, required for making any changes
pub fn tx<F: FnOnce(&mut Transaction<D>) -> Result<T>, T>(&mut self, f: F) -> Result<T> { pub fn tx<F: FnOnce(&mut Transaction<D>) -> Result<T>, T>(&mut self, f: F) -> Result<T> {
let mut tx = Transaction::new(self); let mut tx = Transaction::new(self);
let t = f(&mut tx)?; let t = f(&mut tx)?;
...@@ -223,7 +227,7 @@ impl<D: Disk> FileSystem<D> { ...@@ -223,7 +227,7 @@ impl<D: Disk> FileSystem<D> {
/// Reset allocator to state stored on disk /// Reset allocator to state stored on disk
/// ///
/// # Safety /// # Safety
/// Unsafe, it must only be called when openning the filesystem /// Unsafe, it must only be called when opening the filesystem
unsafe fn reset_allocator(&mut self) -> Result<()> { unsafe fn reset_allocator(&mut self) -> Result<()> {
self.allocator = Allocator::default(); self.allocator = Allocator::default();
...@@ -243,19 +247,18 @@ impl<D: Disk> FileSystem<D> { ...@@ -243,19 +247,18 @@ impl<D: Disk> FileSystem<D> {
for alloc in allocs { for alloc in allocs {
for entry in alloc.data().entries.iter() { for entry in alloc.data().entries.iter() {
let addr = entry.addr(); let index = entry.index();
let count = entry.count(); let count = entry.count();
if count < 0 { if count < 0 {
for i in 0..-count { for i in 0..-count {
//TODO: replace assert with error? //TODO: replace assert with error?
assert_eq!( let addr = BlockAddr::new(index + i as u64, BlockLevel::default());
self.allocator.allocate_exact(addr + i as u64), assert_eq!(self.allocator.allocate_exact(addr), Some(addr));
Some(addr + i as u64)
);
} }
} else { } else {
for i in 0..count { for i in 0..count {
self.allocator.deallocate(addr + i as u64); let addr = BlockAddr::new(index + i as u64, BlockLevel::default());
self.allocator.deallocate(addr);
} }
} }
} }
...@@ -265,52 +268,58 @@ impl<D: Disk> FileSystem<D> { ...@@ -265,52 +268,58 @@ impl<D: Disk> FileSystem<D> {
} }
pub(crate) fn decrypt(&mut self, data: &mut [u8]) -> bool { pub(crate) fn decrypt(&mut self, data: &mut [u8]) -> bool {
if let Some(ref aes) = self.aes_opt { let aes = if let Some(ref aes) = self.aes_opt {
assert_eq!(data.len() % aes::BLOCK_SIZE, 0); aes
} else {
self.aes_blocks.clear(); // Do nothing if encryption is disabled
for i in 0..data.len() / aes::BLOCK_SIZE { return false;
self.aes_blocks.push(aes::Block::clone_from_slice( };
&data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE],
));
}
aes.decrypt_blocks(&mut self.aes_blocks); assert_eq!(data.len() % aes::BLOCK_SIZE, 0);
for i in 0..data.len() / aes::BLOCK_SIZE { self.aes_blocks.clear();
data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE] for i in 0..data.len() / aes::BLOCK_SIZE {
.copy_from_slice(&self.aes_blocks[i]); self.aes_blocks.push(aes::Block::clone_from_slice(
} &data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE],
self.aes_blocks.clear(); ));
}
true aes.decrypt_blocks(&mut self.aes_blocks);
} else {
false for i in 0..data.len() / aes::BLOCK_SIZE {
data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE]
.copy_from_slice(&self.aes_blocks[i]);
} }
self.aes_blocks.clear();
true
} }
pub(crate) fn encrypt(&mut self, data: &mut [u8]) -> bool { pub(crate) fn encrypt(&mut self, data: &mut [u8]) -> bool {
if let Some(ref aes) = self.aes_opt { let aes = if let Some(ref aes) = self.aes_opt {
assert_eq!(data.len() % aes::BLOCK_SIZE, 0); aes
} else {
self.aes_blocks.clear(); // Do nothing if encryption is disabled
for i in 0..data.len() / aes::BLOCK_SIZE { return false;
self.aes_blocks.push(aes::Block::clone_from_slice( };
&data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE],
));
}
aes.encrypt_blocks(&mut self.aes_blocks); assert_eq!(data.len() % aes::BLOCK_SIZE, 0);
for i in 0..data.len() / aes::BLOCK_SIZE { self.aes_blocks.clear();
data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE] for i in 0..data.len() / aes::BLOCK_SIZE {
.copy_from_slice(&self.aes_blocks[i]); self.aes_blocks.push(aes::Block::clone_from_slice(
} &data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE],
self.aes_blocks.clear(); ));
}
true aes.encrypt_blocks(&mut self.aes_blocks);
} else {
false for i in 0..data.len() / aes::BLOCK_SIZE {
data[i * aes::BLOCK_SIZE..(i + 1) * aes::BLOCK_SIZE]
.copy_from_slice(&self.aes_blocks[i]);
} }
self.aes_blocks.clear();
true
} }
} }
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use core::{fmt, mem, slice}; use core::{fmt, mem, slice};
use simple_endian::*; use endian_num::Le;
use aes::{Aes128, BlockDecrypt, BlockEncrypt}; use aes::{Aes128, BlockDecrypt, BlockEncrypt};
use uuid::Uuid;
use crate::{AllocList, BlockPtr, KeySlot, Tree, BLOCK_SIZE, SIGNATURE, VERSION}; use crate::{AllocList, BlockPtr, KeySlot, Tree, BLOCK_SIZE, SIGNATURE, VERSION};
...@@ -11,18 +10,18 @@ pub const HEADER_RING: u64 = 256; ...@@ -11,18 +10,18 @@ pub const HEADER_RING: u64 = 256;
/// The header of the filesystem /// The header of the filesystem
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(packed)] #[repr(C, packed)]
pub struct Header { pub struct Header {
/// Signature, should be SIGNATURE /// Signature, should be SIGNATURE
pub signature: [u8; 8], pub signature: [u8; 8],
/// Version, should be VERSION /// Version, should be VERSION
pub version: u64le, pub version: Le<u64>,
/// Disk ID, a 128-bit unique identifier /// Disk ID, a 128-bit unique identifier
pub uuid: [u8; 16], pub uuid: [u8; 16],
/// Disk size, in number of BLOCK_SIZE sectors /// Disk size, in number of BLOCK_SIZE sectors
pub size: u64le, pub size: Le<u64>,
/// Generation of header /// Generation of header
pub generation: u64le, pub generation: Le<u64>,
/// Block of first tree node /// Block of first tree node
pub tree: BlockPtr<Tree>, pub tree: BlockPtr<Tree>,
/// Block of last alloc node /// Block of last alloc node
...@@ -34,13 +33,13 @@ pub struct Header { ...@@ -34,13 +33,13 @@ pub struct Header {
/// encrypted hash of header data without hash, set to hash and padded if disk is not encrypted /// encrypted hash of header data without hash, set to hash and padded if disk is not encrypted
pub encrypted_hash: [u8; 16], pub encrypted_hash: [u8; 16],
/// hash of header data without hash /// hash of header data without hash
pub hash: u64le, pub hash: Le<u64>,
} }
impl Header { impl Header {
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn new(size: u64) -> Header { pub fn new(size: u64) -> Header {
let uuid = Uuid::new_v4(); let uuid = uuid::Uuid::new_v4();
let mut header = Header { let mut header = Header {
signature: *SIGNATURE, signature: *SIGNATURE,
version: VERSION.into(), version: VERSION.into(),
...@@ -58,12 +57,12 @@ impl Header { ...@@ -58,12 +57,12 @@ impl Header {
return false; return false;
} }
if { self.version }.to_native() != VERSION { if self.version.to_ne() != VERSION {
// Version does not match // Version does not match
return false; return false;
} }
if { self.hash }.to_native() != self.create_hash() { if self.hash.to_ne() != self.create_hash() {
// Hash does not match // Hash does not match
return false; return false;
} }
...@@ -77,11 +76,11 @@ impl Header { ...@@ -77,11 +76,11 @@ impl Header {
} }
pub fn size(&self) -> u64 { pub fn size(&self) -> u64 {
{ self.size }.to_native() self.size.to_ne()
} }
pub fn generation(&self) -> u64 { pub fn generation(&self) -> u64 {
{ self.generation }.to_native() self.generation.to_ne()
} }
fn create_hash(&self) -> u64 { fn create_hash(&self) -> u64 {
...@@ -94,7 +93,7 @@ impl Header { ...@@ -94,7 +93,7 @@ impl Header {
fn create_encrypted_hash(&self, aes_opt: Option<&Aes128>) -> [u8; 16] { fn create_encrypted_hash(&self, aes_opt: Option<&Aes128>) -> [u8; 16] {
let mut encrypted_hash = [0; 16]; let mut encrypted_hash = [0; 16];
for (i, b) in { self.hash }.to_native().to_le_bytes().iter().enumerate() { for (i, b) in self.hash.to_le_bytes().iter().enumerate() {
encrypted_hash[i] = *b; encrypted_hash[i] = *b;
} }
if let Some(aes) = aes_opt { if let Some(aes) = aes_opt {
...@@ -212,7 +211,7 @@ fn header_hash_test() { ...@@ -212,7 +211,7 @@ fn header_hash_test() {
let mut header = Header::default(); let mut header = Header::default();
assert_eq!(header.create_hash(), 0xe81ffcb86026ff96); assert_eq!(header.create_hash(), 0xe81ffcb86026ff96);
header.update_hash(None); header.update_hash(None);
assert_eq!({ header.hash }.to_native(), 0xe81ffcb86026ff96); assert_eq!(header.hash.to_ne(), 0xe81ffcb86026ff96);
assert_eq!( assert_eq!(
header.encrypted_hash, header.encrypted_hash,
[0x96, 0xff, 0x26, 0x60, 0xb8, 0xfc, 0x1f, 0xe8, 0, 0, 0, 0, 0, 0, 0, 0] [0x96, 0xff, 0x26, 0x60, 0xb8, 0xfc, 0x1f, 0xe8, 0, 0, 0, 0, 0, 0, 0, 0]
......
...@@ -40,7 +40,7 @@ impl Salt { ...@@ -40,7 +40,7 @@ impl Salt {
/// The key slot, containing the salt and encrypted key that are used with one password /// The key slot, containing the salt and encrypted key that are used with one password
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
#[repr(packed)] #[repr(C, packed)]
pub struct KeySlot { pub struct KeySlot {
salt: Salt, salt: Salt,
encrypted_key: EncryptedKey, encrypted_key: EncryptedKey,
......
...@@ -3,20 +3,30 @@ ...@@ -3,20 +3,30 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Used often in generating redox_syscall errors // Used often in generating redox_syscall errors
#![allow(clippy::or_fun_call)] #![allow(clippy::or_fun_call)]
#![allow(unexpected_cfgs)]
extern crate alloc; extern crate alloc;
use core::sync::atomic::AtomicUsize; use core::sync::atomic::AtomicUsize;
// The alloc log grows by 1 block about every 21 generations
pub const ALLOC_GC_THRESHOLD: u64 = 1024;
pub const BLOCK_SIZE: u64 = 4096; pub const BLOCK_SIZE: u64 = 4096;
// A record is 4KiB << 5 = 128KiB
pub const RECORD_LEVEL: usize = 5;
pub const RECORD_SIZE: u64 = BLOCK_SIZE << RECORD_LEVEL;
pub const SIGNATURE: &[u8; 8] = b"RedoxFS\0"; pub const SIGNATURE: &[u8; 8] = b"RedoxFS\0";
pub const VERSION: u64 = 5; pub const VERSION: u64 = 6;
pub const DIR_ENTRY_MAX_LENGTH: usize = 252;
pub static IS_UMT: AtomicUsize = AtomicUsize::new(0); pub static IS_UMT: AtomicUsize = AtomicUsize::new(0);
pub use self::allocator::{AllocEntry, AllocList, Allocator, ALLOC_LIST_ENTRIES}; pub use self::allocator::{AllocEntry, AllocList, Allocator, ALLOC_LIST_ENTRIES};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use self::archive::{archive, archive_at}; pub use self::archive::{archive, archive_at};
pub use self::block::{BlockData, BlockList, BlockPtr, BlockRaw}; pub use self::block::{
BlockAddr, BlockData, BlockLevel, BlockList, BlockPtr, BlockRaw, BlockTrait,
};
pub use self::dir::{DirEntry, DirList}; pub use self::dir::{DirEntry, DirList};
pub use self::disk::*; pub use self::disk::*;
pub use self::filesystem::FileSystem; pub use self::filesystem::FileSystem;
...@@ -25,8 +35,10 @@ pub use self::key::{Key, KeySlot, Salt}; ...@@ -25,8 +35,10 @@ pub use self::key::{Key, KeySlot, Salt};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use self::mount::mount; pub use self::mount::mount;
pub use self::node::{Node, NodeLevel}; pub use self::node::{Node, NodeLevel};
pub use self::record::RecordRaw;
pub use self::transaction::Transaction; pub use self::transaction::Transaction;
pub use self::tree::{Tree, TreeData, TreeList, TreePtr}; pub use self::tree::{Tree, TreeData, TreeList, TreePtr};
#[cfg(feature = "std")]
pub use self::unmount::unmount_path; pub use self::unmount::unmount_path;
mod allocator; mod allocator;
...@@ -38,9 +50,12 @@ mod disk; ...@@ -38,9 +50,12 @@ mod disk;
mod filesystem; mod filesystem;
mod header; mod header;
mod key; mod key;
#[cfg(feature = "std")] #[cfg(all(feature = "std", not(fuzzing)))]
mod mount; mod mount;
#[cfg(all(feature = "std", fuzzing))]
pub mod mount;
mod node; mod node;
mod record;
mod transaction; mod transaction;
mod tree; mod tree;
#[cfg(feature = "std")] #[cfg(feature = "std")]
......