├── .github └── workflows │ └── nix.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── crates ├── icfs-fatfs │ ├── Cargo.toml │ ├── lib.rs │ └── time_provider.rs └── icfs │ ├── Cargo.toml │ ├── internal.rs │ ├── lib.rs │ └── stable_memory.rs ├── dfx.json ├── examples ├── fatfs │ ├── Cargo.toml │ ├── fatfs.did │ ├── lib.rs │ └── test.ic-repl └── icfs │ ├── Cargo.toml │ ├── icfs.did │ ├── lib.rs │ └── test.ic-repl ├── flake.lock └── flake.nix /.github/workflows/nix.yml: -------------------------------------------------------------------------------- 1 | name: "Nix" 2 | on: 3 | pull_request: 4 | push: 5 | jobs: 6 | nix: 7 | name: Nix on ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest, macos-latest] 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2.4.0 14 | - uses: cachix/install-nix-action@v15 15 | - run: nix build --show-trace 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # DFINITY 2 | .dfx/ 3 | 4 | 5 | # Nix 6 | result 7 | result-* 8 | 9 | 10 | # Rust 11 | # https://github.com/github/gitignore/blob/master/Rust.gitignore 12 | 13 | # Generated by Cargo 14 | # will have compiled files and executables 15 | debug/ 16 | target/ 17 | 18 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 19 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 20 | # Cargo.lock 21 | 22 | # These are backup files generated by rustfmt 23 | **/*.rs.bk 24 | 25 | # MSVC Windows builds of rustc generate these, which store debugging information 26 | *.pdb -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anyhow" 16 | version = "1.0.53" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" 19 | 20 | [[package]] 21 | name = "arrayvec" 22 | version = "0.5.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 25 | 26 | [[package]] 27 | name = "ascii-canvas" 28 | version = "3.0.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" 31 | dependencies = [ 32 | "term", 33 | ] 34 | 35 | [[package]] 36 | name = "atty" 37 | version = "0.2.14" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 40 | dependencies = [ 41 | "hermit-abi", 42 | "libc", 43 | "winapi", 44 | ] 45 | 46 | [[package]] 47 | name = "autocfg" 48 | version = "1.1.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 51 | 52 | [[package]] 53 | name = "base32" 54 | version = "0.4.0" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" 57 | 58 | [[package]] 59 | name = "beef" 60 | version = "0.5.1" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736" 63 | 64 | [[package]] 65 | name = "binread" 66 | version = "2.2.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" 69 | dependencies = [ 70 | "binread_derive", 71 | "lazy_static", 72 | "rustversion", 73 | ] 74 | 75 | [[package]] 76 | name = "binread_derive" 77 | version = "2.1.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" 80 | dependencies = [ 81 | "either", 82 | "proc-macro2", 83 | "quote", 84 | "syn", 85 | ] 86 | 87 | [[package]] 88 | name = "bit-set" 89 | version = "0.5.2" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" 92 | dependencies = [ 93 | "bit-vec", 94 | ] 95 | 96 | [[package]] 97 | name = "bit-vec" 98 | version = "0.6.3" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 101 | 102 | [[package]] 103 | name = "bitflags" 104 | version = "1.3.2" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 107 | 108 | [[package]] 109 | name = "block-buffer" 110 | version = "0.9.0" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 113 | dependencies = [ 114 | "generic-array", 115 | ] 116 | 117 | [[package]] 118 | name = "byteorder" 119 | version = "1.4.3" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 122 | 123 | [[package]] 124 | name = "candid" 125 | version = "0.7.11" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "f5531982124b31420dc41d0c8c0abbdd03e97d561dfb2af027b9140ee2b1f50c" 128 | dependencies = [ 129 | "anyhow", 130 | "binread", 131 | "byteorder", 132 | "candid_derive", 133 | "codespan-reporting", 134 | "hex", 135 | "ic-types", 136 | "lalrpop", 137 | "lalrpop-util", 138 | "leb128", 139 | "logos", 140 | "num-bigint", 141 | "num-traits", 142 | "num_enum", 143 | "paste", 144 | "pretty", 145 | "serde", 146 | "serde_bytes", 147 | "thiserror", 148 | ] 149 | 150 | [[package]] 151 | name = "candid_derive" 152 | version = "0.4.5" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "2e02c03c4d547674a3f3f3109538fb49871fbe636216daa019f06a62faca9061" 155 | dependencies = [ 156 | "lazy_static", 157 | "proc-macro2", 158 | "quote", 159 | "syn", 160 | ] 161 | 162 | [[package]] 163 | name = "cfg-if" 164 | version = "1.0.0" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 167 | 168 | [[package]] 169 | name = "chrono" 170 | version = "0.4.19" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 173 | dependencies = [ 174 | "libc", 175 | "num-integer", 176 | "num-traits", 177 | "time 0.1.43", 178 | "winapi", 179 | ] 180 | 181 | [[package]] 182 | name = "codespan-reporting" 183 | version = "0.11.1" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" 186 | dependencies = [ 187 | "termcolor", 188 | "unicode-width", 189 | ] 190 | 191 | [[package]] 192 | name = "cpufeatures" 193 | version = "0.2.1" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 196 | dependencies = [ 197 | "libc", 198 | ] 199 | 200 | [[package]] 201 | name = "crc32fast" 202 | version = "1.3.2" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 205 | dependencies = [ 206 | "cfg-if", 207 | ] 208 | 209 | [[package]] 210 | name = "crunchy" 211 | version = "0.2.2" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 214 | 215 | [[package]] 216 | name = "diff" 217 | version = "0.1.12" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" 220 | 221 | [[package]] 222 | name = "digest" 223 | version = "0.9.0" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 226 | dependencies = [ 227 | "generic-array", 228 | ] 229 | 230 | [[package]] 231 | name = "dirs-next" 232 | version = "2.0.0" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" 235 | dependencies = [ 236 | "cfg-if", 237 | "dirs-sys-next", 238 | ] 239 | 240 | [[package]] 241 | name = "dirs-sys-next" 242 | version = "0.1.2" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" 245 | dependencies = [ 246 | "libc", 247 | "redox_users", 248 | "winapi", 249 | ] 250 | 251 | [[package]] 252 | name = "either" 253 | version = "1.6.1" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 256 | 257 | [[package]] 258 | name = "ena" 259 | version = "0.14.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" 262 | dependencies = [ 263 | "log", 264 | ] 265 | 266 | [[package]] 267 | name = "fatfs" 268 | version = "0.4.0" 269 | source = "git+https://github.com/rafalh/rust-fatfs?rev=87fc1ed5074a32b4e0344fcdde77359ef9e75432#87fc1ed5074a32b4e0344fcdde77359ef9e75432" 270 | dependencies = [ 271 | "bitflags", 272 | "chrono", 273 | "log", 274 | ] 275 | 276 | [[package]] 277 | name = "fatfs-example" 278 | version = "0.1.0" 279 | dependencies = [ 280 | "fatfs", 281 | "fscommon", 282 | "ic-cdk 0.4.0", 283 | "ic-cdk-macros", 284 | "icfs", 285 | "icfs-fatfs", 286 | ] 287 | 288 | [[package]] 289 | name = "fixedbitset" 290 | version = "0.2.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" 293 | 294 | [[package]] 295 | name = "fnv" 296 | version = "1.0.7" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 299 | 300 | [[package]] 301 | name = "fscommon" 302 | version = "0.1.1" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "315ce685aca5ddcc5a3e7e436ef47d4a5d0064462849b6f0f628c28140103531" 305 | dependencies = [ 306 | "log", 307 | ] 308 | 309 | [[package]] 310 | name = "generic-array" 311 | version = "0.14.5" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 314 | dependencies = [ 315 | "typenum", 316 | "version_check", 317 | ] 318 | 319 | [[package]] 320 | name = "getrandom" 321 | version = "0.2.4" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" 324 | dependencies = [ 325 | "cfg-if", 326 | "libc", 327 | "wasi", 328 | ] 329 | 330 | [[package]] 331 | name = "hashbrown" 332 | version = "0.11.2" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 335 | 336 | [[package]] 337 | name = "hermit-abi" 338 | version = "0.1.19" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 341 | dependencies = [ 342 | "libc", 343 | ] 344 | 345 | [[package]] 346 | name = "hex" 347 | version = "0.4.3" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 350 | 351 | [[package]] 352 | name = "ic-cdk" 353 | version = "0.3.3" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "606276ed1ce363eb9ccaf492e36fb40425417dcd4598f261d47e0ed6a1309faa" 356 | dependencies = [ 357 | "candid", 358 | "cfg-if", 359 | "serde", 360 | ] 361 | 362 | [[package]] 363 | name = "ic-cdk" 364 | version = "0.4.0" 365 | source = "git+https://github.com/dfinity/cdk-rs.git?rev=a253119adb08929b6304d007ee0a6a37960656ed#a253119adb08929b6304d007ee0a6a37960656ed" 366 | dependencies = [ 367 | "candid", 368 | "cfg-if", 369 | "serde", 370 | ] 371 | 372 | [[package]] 373 | name = "ic-cdk-macros" 374 | version = "0.3.3" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "08bac2578a4779c3ae6d24c766ec7127872d73f29a9e7d70b6607a2fdedd0dde" 377 | dependencies = [ 378 | "candid", 379 | "ic-cdk 0.3.3", 380 | "proc-macro2", 381 | "quote", 382 | "serde", 383 | "serde_tokenstream", 384 | "syn", 385 | ] 386 | 387 | [[package]] 388 | name = "ic-types" 389 | version = "0.3.0" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "0e78ec6f58886cdc252d6f912dc794211bd6bbc39ddc9dcda434b2dc16c335b3" 392 | dependencies = [ 393 | "base32", 394 | "crc32fast", 395 | "hex", 396 | "serde", 397 | "serde_bytes", 398 | "sha2", 399 | "thiserror", 400 | ] 401 | 402 | [[package]] 403 | name = "icfs" 404 | version = "0.1.0" 405 | dependencies = [ 406 | "ic-cdk 0.4.0", 407 | ] 408 | 409 | [[package]] 410 | name = "icfs-example" 411 | version = "0.1.0" 412 | dependencies = [ 413 | "ic-cdk 0.4.0", 414 | "ic-cdk-macros", 415 | "icfs", 416 | ] 417 | 418 | [[package]] 419 | name = "icfs-fatfs" 420 | version = "0.1.0" 421 | dependencies = [ 422 | "fatfs", 423 | "ic-cdk 0.4.0", 424 | "time 0.3.7", 425 | ] 426 | 427 | [[package]] 428 | name = "indexmap" 429 | version = "1.8.0" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" 432 | dependencies = [ 433 | "autocfg", 434 | "hashbrown", 435 | ] 436 | 437 | [[package]] 438 | name = "instant" 439 | version = "0.1.12" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 442 | dependencies = [ 443 | "cfg-if", 444 | ] 445 | 446 | [[package]] 447 | name = "itertools" 448 | version = "0.10.3" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 451 | dependencies = [ 452 | "either", 453 | ] 454 | 455 | [[package]] 456 | name = "lalrpop" 457 | version = "0.19.7" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "852b75a095da6b69da8c5557731c3afd06525d4f655a4fc1c799e2ec8bc4dce4" 460 | dependencies = [ 461 | "ascii-canvas", 462 | "atty", 463 | "bit-set", 464 | "diff", 465 | "ena", 466 | "itertools", 467 | "lalrpop-util", 468 | "petgraph", 469 | "pico-args", 470 | "regex", 471 | "regex-syntax", 472 | "string_cache", 473 | "term", 474 | "tiny-keccak", 475 | "unicode-xid", 476 | ] 477 | 478 | [[package]] 479 | name = "lalrpop-util" 480 | version = "0.19.7" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "d6d265705249fe209280676d8f68887859fa42e1d34f342fc05bd47726a5e188" 483 | dependencies = [ 484 | "regex", 485 | ] 486 | 487 | [[package]] 488 | name = "lazy_static" 489 | version = "1.4.0" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 492 | 493 | [[package]] 494 | name = "leb128" 495 | version = "0.2.5" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" 498 | 499 | [[package]] 500 | name = "libc" 501 | version = "0.2.118" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" 504 | 505 | [[package]] 506 | name = "lock_api" 507 | version = "0.4.6" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 510 | dependencies = [ 511 | "scopeguard", 512 | ] 513 | 514 | [[package]] 515 | name = "log" 516 | version = "0.4.14" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 519 | dependencies = [ 520 | "cfg-if", 521 | ] 522 | 523 | [[package]] 524 | name = "logos" 525 | version = "0.12.0" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "427e2abca5be13136da9afdbf874e6b34ad9001dd70f2b103b083a85daa7b345" 528 | dependencies = [ 529 | "logos-derive", 530 | ] 531 | 532 | [[package]] 533 | name = "logos-derive" 534 | version = "0.12.0" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "56a7d287fd2ac3f75b11f19a1c8a874a7d55744bd91f7a1b3e7cf87d4343c36d" 537 | dependencies = [ 538 | "beef", 539 | "fnv", 540 | "proc-macro2", 541 | "quote", 542 | "regex-syntax", 543 | "syn", 544 | "utf8-ranges", 545 | ] 546 | 547 | [[package]] 548 | name = "memchr" 549 | version = "2.4.1" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 552 | 553 | [[package]] 554 | name = "new_debug_unreachable" 555 | version = "1.0.4" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" 558 | 559 | [[package]] 560 | name = "num-bigint" 561 | version = "0.4.3" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 564 | dependencies = [ 565 | "autocfg", 566 | "num-integer", 567 | "num-traits", 568 | ] 569 | 570 | [[package]] 571 | name = "num-integer" 572 | version = "0.1.44" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 575 | dependencies = [ 576 | "autocfg", 577 | "num-traits", 578 | ] 579 | 580 | [[package]] 581 | name = "num-traits" 582 | version = "0.2.14" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 585 | dependencies = [ 586 | "autocfg", 587 | ] 588 | 589 | [[package]] 590 | name = "num_enum" 591 | version = "0.5.6" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" 594 | dependencies = [ 595 | "num_enum_derive", 596 | ] 597 | 598 | [[package]] 599 | name = "num_enum_derive" 600 | version = "0.5.6" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" 603 | dependencies = [ 604 | "proc-macro-crate", 605 | "proc-macro2", 606 | "quote", 607 | "syn", 608 | ] 609 | 610 | [[package]] 611 | name = "num_threads" 612 | version = "0.1.5" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" 615 | dependencies = [ 616 | "libc", 617 | ] 618 | 619 | [[package]] 620 | name = "opaque-debug" 621 | version = "0.3.0" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 624 | 625 | [[package]] 626 | name = "parking_lot" 627 | version = "0.11.2" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 630 | dependencies = [ 631 | "instant", 632 | "lock_api", 633 | "parking_lot_core", 634 | ] 635 | 636 | [[package]] 637 | name = "parking_lot_core" 638 | version = "0.8.5" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 641 | dependencies = [ 642 | "cfg-if", 643 | "instant", 644 | "libc", 645 | "redox_syscall", 646 | "smallvec", 647 | "winapi", 648 | ] 649 | 650 | [[package]] 651 | name = "paste" 652 | version = "1.0.6" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" 655 | 656 | [[package]] 657 | name = "petgraph" 658 | version = "0.5.1" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" 661 | dependencies = [ 662 | "fixedbitset", 663 | "indexmap", 664 | ] 665 | 666 | [[package]] 667 | name = "phf_shared" 668 | version = "0.10.0" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 671 | dependencies = [ 672 | "siphasher", 673 | ] 674 | 675 | [[package]] 676 | name = "pico-args" 677 | version = "0.4.2" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" 680 | 681 | [[package]] 682 | name = "precomputed-hash" 683 | version = "0.1.1" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 686 | 687 | [[package]] 688 | name = "pretty" 689 | version = "0.10.0" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "ad9940b913ee56ddd94aec2d3cd179dd47068236f42a1a6415ccf9d880ce2a61" 692 | dependencies = [ 693 | "arrayvec", 694 | "typed-arena", 695 | ] 696 | 697 | [[package]] 698 | name = "proc-macro-crate" 699 | version = "1.1.2" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "9dada8c9981fcf32929c3c0f0cd796a9284aca335565227ed88c83babb1d43dc" 702 | dependencies = [ 703 | "thiserror", 704 | "toml", 705 | ] 706 | 707 | [[package]] 708 | name = "proc-macro2" 709 | version = "1.0.36" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 712 | dependencies = [ 713 | "unicode-xid", 714 | ] 715 | 716 | [[package]] 717 | name = "quote" 718 | version = "1.0.15" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" 721 | dependencies = [ 722 | "proc-macro2", 723 | ] 724 | 725 | [[package]] 726 | name = "redox_syscall" 727 | version = "0.2.10" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 730 | dependencies = [ 731 | "bitflags", 732 | ] 733 | 734 | [[package]] 735 | name = "redox_users" 736 | version = "0.4.0" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" 739 | dependencies = [ 740 | "getrandom", 741 | "redox_syscall", 742 | ] 743 | 744 | [[package]] 745 | name = "regex" 746 | version = "1.5.4" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 749 | dependencies = [ 750 | "aho-corasick", 751 | "memchr", 752 | "regex-syntax", 753 | ] 754 | 755 | [[package]] 756 | name = "regex-syntax" 757 | version = "0.6.25" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 760 | 761 | [[package]] 762 | name = "rustversion" 763 | version = "1.0.6" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" 766 | 767 | [[package]] 768 | name = "scopeguard" 769 | version = "1.1.0" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 772 | 773 | [[package]] 774 | name = "serde" 775 | version = "1.0.136" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" 778 | dependencies = [ 779 | "serde_derive", 780 | ] 781 | 782 | [[package]] 783 | name = "serde_bytes" 784 | version = "0.11.5" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" 787 | dependencies = [ 788 | "serde", 789 | ] 790 | 791 | [[package]] 792 | name = "serde_derive" 793 | version = "1.0.136" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" 796 | dependencies = [ 797 | "proc-macro2", 798 | "quote", 799 | "syn", 800 | ] 801 | 802 | [[package]] 803 | name = "serde_tokenstream" 804 | version = "0.1.3" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "d6deb15c3a535e81438110111d90168d91721652f502abb147f31cde129f683d" 807 | dependencies = [ 808 | "proc-macro2", 809 | "serde", 810 | "syn", 811 | ] 812 | 813 | [[package]] 814 | name = "sha2" 815 | version = "0.9.9" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 818 | dependencies = [ 819 | "block-buffer", 820 | "cfg-if", 821 | "cpufeatures", 822 | "digest", 823 | "opaque-debug", 824 | ] 825 | 826 | [[package]] 827 | name = "siphasher" 828 | version = "0.3.9" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" 831 | 832 | [[package]] 833 | name = "smallvec" 834 | version = "1.8.0" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 837 | 838 | [[package]] 839 | name = "string_cache" 840 | version = "0.8.3" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" 843 | dependencies = [ 844 | "lazy_static", 845 | "new_debug_unreachable", 846 | "parking_lot", 847 | "phf_shared", 848 | "precomputed-hash", 849 | ] 850 | 851 | [[package]] 852 | name = "syn" 853 | version = "1.0.86" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" 856 | dependencies = [ 857 | "proc-macro2", 858 | "quote", 859 | "unicode-xid", 860 | ] 861 | 862 | [[package]] 863 | name = "term" 864 | version = "0.7.0" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" 867 | dependencies = [ 868 | "dirs-next", 869 | "rustversion", 870 | "winapi", 871 | ] 872 | 873 | [[package]] 874 | name = "termcolor" 875 | version = "1.1.2" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 878 | dependencies = [ 879 | "winapi-util", 880 | ] 881 | 882 | [[package]] 883 | name = "thiserror" 884 | version = "1.0.30" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 887 | dependencies = [ 888 | "thiserror-impl", 889 | ] 890 | 891 | [[package]] 892 | name = "thiserror-impl" 893 | version = "1.0.30" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 896 | dependencies = [ 897 | "proc-macro2", 898 | "quote", 899 | "syn", 900 | ] 901 | 902 | [[package]] 903 | name = "time" 904 | version = "0.1.43" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 907 | dependencies = [ 908 | "libc", 909 | "winapi", 910 | ] 911 | 912 | [[package]] 913 | name = "time" 914 | version = "0.3.7" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" 917 | dependencies = [ 918 | "libc", 919 | "num_threads", 920 | ] 921 | 922 | [[package]] 923 | name = "tiny-keccak" 924 | version = "2.0.2" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 927 | dependencies = [ 928 | "crunchy", 929 | ] 930 | 931 | [[package]] 932 | name = "toml" 933 | version = "0.5.8" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 936 | dependencies = [ 937 | "serde", 938 | ] 939 | 940 | [[package]] 941 | name = "typed-arena" 942 | version = "2.0.1" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" 945 | 946 | [[package]] 947 | name = "typenum" 948 | version = "1.15.0" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 951 | 952 | [[package]] 953 | name = "unicode-width" 954 | version = "0.1.9" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 957 | 958 | [[package]] 959 | name = "unicode-xid" 960 | version = "0.2.2" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 963 | 964 | [[package]] 965 | name = "utf8-ranges" 966 | version = "1.0.4" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba" 969 | 970 | [[package]] 971 | name = "version_check" 972 | version = "0.9.4" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 975 | 976 | [[package]] 977 | name = "wasi" 978 | version = "0.10.2+wasi-snapshot-preview1" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 981 | 982 | [[package]] 983 | name = "winapi" 984 | version = "0.3.9" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 987 | dependencies = [ 988 | "winapi-i686-pc-windows-gnu", 989 | "winapi-x86_64-pc-windows-gnu", 990 | ] 991 | 992 | [[package]] 993 | name = "winapi-i686-pc-windows-gnu" 994 | version = "0.4.0" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 997 | 998 | [[package]] 999 | name = "winapi-util" 1000 | version = "0.1.5" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1003 | dependencies = [ 1004 | "winapi", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "winapi-x86_64-pc-windows-gnu" 1009 | version = "0.4.0" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1012 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "crates/icfs", 4 | "crates/icfs-fatfs", 5 | "examples/icfs", 6 | "examples/fatfs", 7 | ] 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 Paul Young 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # icfs 2 | 3 | Internet Computer File System 4 | 5 | ![](https://img.shields.io/badge/status%EF%B8%8F-experimental-blueviolet) 6 | 7 | ## Crates 8 | 9 | * `icfs` provides implementations of `std::io::{Read, Write, Seek}` backed by stable memory to enable the use of existing Rust code that requires implementations of these traits. 10 | * `icfs-fatfs` uses `icfs` to leverage the `fatfs` crate in providing a FAT file system. All this currently does is implement a `fatfs::TimeProvider` backed by `ic_cdk::api::time()` 11 | 12 | ## Develop 13 | 14 | `nix develop` 15 | 16 | ## Build 17 | 18 | `nix build` or `nix build '.#package-name'` 19 | -------------------------------------------------------------------------------- /crates/icfs-fatfs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "icfs-fatfs" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Paul Young <84700+paulyoung@users.noreply.github.com>"] 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | path = "lib.rs" 11 | crate-type = ["cdylib", "lib"] 12 | 13 | [dependencies] 14 | fatfs = { git = "https://github.com/rafalh/rust-fatfs", rev = "87fc1ed5074a32b4e0344fcdde77359ef9e75432" } 15 | ic-cdk = { git = "https://github.com/dfinity/cdk-rs.git", rev = "a253119adb08929b6304d007ee0a6a37960656ed" } 16 | time = "0.3" -------------------------------------------------------------------------------- /crates/icfs-fatfs/lib.rs: -------------------------------------------------------------------------------- 1 | mod time_provider; 2 | pub use time_provider::TimeProvider; 3 | 4 | -------------------------------------------------------------------------------- /crates/icfs-fatfs/time_provider.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | #[derive(Debug, Clone, Copy, Default)] 4 | pub struct TimeProvider { 5 | _dummy: (), 6 | } 7 | 8 | impl TimeProvider { 9 | #[must_use] 10 | pub fn new() -> Self { 11 | Self { _dummy: () } 12 | } 13 | } 14 | 15 | impl fatfs::TimeProvider for TimeProvider { 16 | fn get_current_date(&self) -> fatfs::Date { 17 | self.get_current_date_time().date 18 | } 19 | 20 | fn get_current_date_time(&self) -> fatfs::DateTime { 21 | let ns = time::Duration::nanoseconds(ic_cdk::api::time() as i64); 22 | 23 | let epoch = time::PrimitiveDateTime::new( 24 | time::Date::from_calendar_date(1970, time::Month::January, 1).unwrap(), 25 | time::Time::from_hms(0, 0, 0).unwrap(), 26 | ); 27 | 28 | let datetime = epoch.checked_add(ns).unwrap(); 29 | 30 | // NOTE: fatfs only supports years in the range [1980, 2107] 31 | let year: u16 = datetime.year().try_into().unwrap(); 32 | 33 | let month = match datetime.month() { 34 | time::Month::January => 1, 35 | time::Month::February => 2, 36 | time::Month::March => 3, 37 | time::Month::April => 4, 38 | time::Month::May => 5, 39 | time::Month::June => 6, 40 | time::Month::July => 7, 41 | time::Month::August => 8, 42 | time::Month::September => 9, 43 | time::Month::October => 10, 44 | time::Month::November => 11, 45 | time::Month::December => 12, 46 | }; 47 | 48 | let day = datetime.day() as u16; 49 | 50 | let hour = datetime.hour() as u16; 51 | let min = datetime.minute() as u16; 52 | let sec = datetime.second() as u16; 53 | let millis = datetime.millisecond() as u16; 54 | 55 | fatfs::DateTime::new( 56 | fatfs::Date::new(year, month, day), 57 | fatfs::Time::new(hour, min, sec, millis), 58 | ) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /crates/icfs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "icfs" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Paul Young <84700+paulyoung@users.noreply.github.com>"] 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | path = "lib.rs" 11 | crate-type = ["cdylib", "lib"] 12 | 13 | [dependencies] 14 | ic-cdk = { git = "https://github.com/dfinity/cdk-rs.git", rev = "a253119adb08929b6304d007ee0a6a37960656ed" } -------------------------------------------------------------------------------- /crates/icfs/internal.rs: -------------------------------------------------------------------------------- 1 | // Copied from: https://github.com/rust-lang/rust/blob/a2af9cf1cf6ccb195eae40cdd793939bc77e7e73/library/std/src/io/mod.rs#L356 2 | // This may be avoidable in future: https://github.com/rust-lang/rfcs/pull/1210 3 | pub (crate) fn default_read_to_end(r: &mut R, buf: &mut Vec) -> std::io::Result { 4 | let start_len = buf.len(); 5 | let start_cap = buf.capacity(); 6 | 7 | let mut initialized = 0; // Extra initialized bytes from previous loop iteration 8 | loop { 9 | if buf.len() == buf.capacity() { 10 | buf.reserve(32); // buf is full, need more space 11 | } 12 | 13 | let mut read_buf = std::io::ReadBuf::uninit(buf.spare_capacity_mut()); 14 | 15 | // SAFETY: These bytes were initialized but not filled in the previous loop 16 | unsafe { 17 | read_buf.assume_init(initialized); 18 | } 19 | 20 | match r.read_buf(&mut read_buf) { 21 | Ok(()) => {} 22 | Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue, 23 | Err(e) => return Err(e), 24 | } 25 | 26 | if read_buf.filled_len() == 0 { 27 | return Ok(buf.len() - start_len); 28 | } 29 | 30 | // store how much was initialized but not filled 31 | initialized = read_buf.initialized_len() - read_buf.filled_len(); 32 | let new_len = read_buf.filled_len() + buf.len(); 33 | 34 | // SAFETY: ReadBuf's invariants mean this much memory is init 35 | unsafe { 36 | buf.set_len(new_len); 37 | } 38 | 39 | if buf.len() == buf.capacity() && buf.capacity() == start_cap { 40 | // The buffer might be an exact fit. Let's read into a probe buffer 41 | // and see if it returns `Ok(0)`. If so, we've avoided an 42 | // unnecessary doubling of the capacity. But if not, append the 43 | // probe buffer to the primary buffer and let its capacity grow. 44 | let mut probe = [0u8; 32]; 45 | 46 | loop { 47 | match r.read(&mut probe) { 48 | Ok(0) => return Ok(buf.len() - start_len), 49 | Ok(n) => { 50 | buf.extend_from_slice(&probe[..n]); 51 | break; 52 | } 53 | Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, 54 | Err(e) => return Err(e), 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/icfs/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(read_buf)] 2 | #![feature(result_flattening)] 3 | 4 | mod internal; 5 | mod stable_memory; 6 | pub use stable_memory::StableMemory; 7 | -------------------------------------------------------------------------------- /crates/icfs/stable_memory.rs: -------------------------------------------------------------------------------- 1 | // Based on https://github.com/dfinity/cdk-rs/blob/a253119adb08929b6304d007ee0a6a37960656ed/src/ic-cdk/src/api/stable.rs 2 | // * Supports 64-bit addressed memory 3 | use ic_cdk::api::stable::{ 4 | stable64_read, stable64_write, StableMemoryError, 5 | }; 6 | use std::io; 7 | 8 | const WASM_PAGE_SIZE_IN_BYTES: u64 = 64 * 1024; // 64KB 9 | 10 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 11 | pub struct StableMemory { 12 | offset: usize, 13 | } 14 | 15 | fn get_offset(stable_memory: &StableMemory) -> usize { 16 | stable_memory.offset 17 | } 18 | 19 | fn set_offset(stable_memory: &mut StableMemory, offset: usize) { 20 | stable_memory.offset = offset 21 | } 22 | 23 | /// Returns a copy of the stable memory. 24 | /// 25 | /// This will map the whole memory (even if not all of it has been written to). 26 | pub fn bytes() -> Vec { 27 | let capacity = capacity(); 28 | let mut vec = Vec::with_capacity(capacity); 29 | unsafe { 30 | vec.set_len(capacity); 31 | } 32 | stable64_read(0, vec.as_mut_slice()); 33 | vec 34 | } 35 | 36 | /// Gets capacity of the stable memory in bytes. 37 | pub fn capacity() -> usize { 38 | (size() as usize) << 16 39 | } 40 | 41 | /// Attempts to grow the memory by adding new pages. 42 | pub fn grow(added_pages: u64) -> Result { 43 | ic_cdk::api::stable::stable64_grow(added_pages) 44 | } 45 | 46 | /// Gets current size of the stable memory in WebAssembly pages. 47 | pub fn size() -> u64 { 48 | ic_cdk::api::stable::stable64_size() 49 | } 50 | 51 | /// Reads data from the stable memory location specified by an offset. 52 | pub fn read(stable_memory: &mut StableMemory, buf: &mut [u8]) -> Result { 53 | let offset = get_offset(stable_memory); 54 | let capacity = capacity(); 55 | let read_buf = if buf.len() + offset > capacity { 56 | if offset <= capacity { 57 | &mut buf[..capacity - offset] 58 | } else { 59 | return Err(StableMemoryError::OutOfBounds); 60 | } 61 | } else { 62 | buf 63 | }; 64 | stable64_read(offset as u64, read_buf); 65 | set_offset(stable_memory, offset + read_buf.len()); 66 | Ok(read_buf.len()) 67 | } 68 | 69 | fn seek(stable_memory: &mut StableMemory, pos: io::SeekFrom) -> Result { 70 | match pos { 71 | io::SeekFrom::Start(start) => { 72 | set_offset(stable_memory, start as usize); 73 | Ok(get_offset(stable_memory) as u64) 74 | } 75 | io::SeekFrom::End(end) => { 76 | let new_offset = capacity() as i64 + end; 77 | if new_offset >= 0 { 78 | set_offset(stable_memory, new_offset as usize); 79 | Ok(get_offset(stable_memory) as u64) 80 | } else { 81 | Err(StableMemoryError::OutOfBounds) 82 | } 83 | } 84 | io::SeekFrom::Current(current) => { 85 | let new_offset = get_offset(stable_memory) as i64 + current; 86 | if new_offset >= 0 { 87 | set_offset(stable_memory, new_offset as usize); 88 | Ok(get_offset(stable_memory) as u64) 89 | } else { 90 | Err(StableMemoryError::OutOfBounds) 91 | } 92 | } 93 | } 94 | } 95 | 96 | /// Writes a byte slice to the buffer. 97 | /// 98 | /// The only condition where this will 99 | /// error out is if it cannot grow the memory. 100 | pub fn write(stable_memory: &mut StableMemory, buf: &[u8]) -> Result { 101 | let offset = get_offset(stable_memory); 102 | let memory_end_bytes = offset + buf.len(); 103 | let memory_end_pages = 104 | (memory_end_bytes as u64 + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES; 105 | let additional_pages_required = memory_end_pages.saturating_sub(capacity() as u64); 106 | if additional_pages_required > 0 { 107 | grow(additional_pages_required)?; 108 | } 109 | let capacity = capacity(); 110 | let write_buf = if memory_end_bytes > capacity { 111 | if offset <= capacity { 112 | &buf[..capacity - offset] 113 | } else { 114 | return Err(StableMemoryError::OutOfBounds); 115 | } 116 | } else { 117 | buf 118 | }; 119 | stable64_write(offset as u64, write_buf); 120 | let new_offset = offset + write_buf.len(); 121 | set_offset(stable_memory, new_offset); 122 | Ok(write_buf.len()) 123 | } 124 | 125 | impl StableMemory { 126 | /// Returns a copy of the stable memory. 127 | /// 128 | /// This will map the whole memory (even if not all of it has been written to). 129 | pub fn bytes() -> Vec { 130 | bytes() 131 | } 132 | 133 | /// Gets capacity of the stable memory in bytes. 134 | pub fn capacity() -> usize { 135 | capacity() 136 | } 137 | 138 | /// Attempts to grow the memory by adding new pages. 139 | pub fn grow(added_pages: u64) -> std::io::Result { 140 | grow(added_pages).map_err(|_| { 141 | std::io::Error::new(std::io::ErrorKind::Other, "Unable to grow stable memory") 142 | }) 143 | } 144 | 145 | /// Gets current size of the stable memory in WebAssembly pages. 146 | pub fn size() -> u64 { 147 | size() 148 | } 149 | } 150 | 151 | impl Default for StableMemory { 152 | fn default() -> Self { 153 | Self { offset: 0 } 154 | } 155 | } 156 | 157 | impl std::io::Read for StableMemory { 158 | fn read(&mut self, buf: &mut [u8]) -> std::io::Result { 159 | read(self, buf).map_err(|e| io::Error::new(io::ErrorKind::Other, e)) 160 | } 161 | 162 | fn read_to_end(&mut self, buf: &mut Vec) -> std::io::Result { 163 | crate::internal::default_read_to_end(self, buf).or(Ok(0)) // Read defines EOF to be success 164 | } 165 | } 166 | 167 | impl std::io::Write for StableMemory { 168 | fn write(&mut self, buf: &[u8]) -> std::io::Result { 169 | write(self, buf).map_err(|e| io::Error::new(io::ErrorKind::OutOfMemory, e)) 170 | } 171 | 172 | fn flush(&mut self) -> std::io::Result<()> { 173 | // No-op. 174 | Ok(()) 175 | } 176 | } 177 | 178 | impl std::io::Seek for StableMemory { 179 | fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { 180 | seek(self, pos) 181 | .map_err(|_| io::Error::new(io::ErrorKind::Other, "Attempt to seek before byte 0")) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /dfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dfx": "0.8.4", 4 | "canisters": { 5 | "icfs": { 6 | "type": "custom", 7 | "build": "nix build '.#icfs-example'", 8 | "candid": "examples/icfs/icfs.did", 9 | "wasm": "result/lib/icfs_example.wasm" 10 | }, 11 | "fatfs": { 12 | "type": "custom", 13 | "build": "nix build '.#fatfs-example'", 14 | "candid": "examples/fatfs/fatfs.did", 15 | "wasm": "result/lib/fatfs_example.wasm" 16 | } 17 | }, 18 | "networks": { 19 | "local": { 20 | "bind": "127.0.0.1:8000", 21 | "type": "ephemeral" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/fatfs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fatfs-example" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Paul Young <84700+paulyoung@users.noreply.github.com>"] 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | path = "lib.rs" 11 | crate-type = ["cdylib", "lib"] 12 | 13 | [dependencies] 14 | fatfs = { git = "https://github.com/rafalh/rust-fatfs", rev = "87fc1ed5074a32b4e0344fcdde77359ef9e75432" } 15 | fscommon = "0.1" 16 | ic-cdk = { git = "https://github.com/dfinity/cdk-rs.git", rev = "a253119adb08929b6304d007ee0a6a37960656ed" } 17 | ic-cdk-macros = "0.3" 18 | icfs = { path = "../../crates/icfs" } 19 | icfs-fatfs = { path = "../../crates/icfs-fatfs" } -------------------------------------------------------------------------------- /examples/fatfs/fatfs.did: -------------------------------------------------------------------------------- 1 | service : { 2 | cat : (path : text) -> (text) query; 3 | ls : (path : text) -> (vec text) query; 4 | mkdir : (path : text) -> (); 5 | rm : (path : text) -> (); 6 | write_file : (path : text, contents : text) -> (); 7 | } -------------------------------------------------------------------------------- /examples/fatfs/lib.rs: -------------------------------------------------------------------------------- 1 | use ic_cdk_macros::{query, update}; 2 | use std::io::{Read, Write}; 3 | 4 | #[cfg(target_arch = "wasm32")] 5 | use std::convert::TryInto; 6 | 7 | // type FileSystem = fatfs::FileSystem< 8 | // fatfs::StdIoWrapper>, 9 | // icfs_fatfs::TimeProvider, 10 | // fatfs::LossyOemCpConverter, 11 | // >; 12 | type FileSystem = fatfs::FileSystem< 13 | fatfs::StdIoWrapper, 14 | icfs_fatfs::TimeProvider, 15 | fatfs::LossyOemCpConverter, 16 | >; 17 | 18 | type Dir<'a> = fatfs::Dir< 19 | 'a, 20 | fatfs::StdIoWrapper, 21 | icfs_fatfs::TimeProvider, 22 | fatfs::LossyOemCpConverter, 23 | >; 24 | 25 | thread_local! { 26 | // static STABLE_MEMORY: std::cell::RefCell> 27 | // = std::cell::RefCell::new(fscommon::BufStream::new(icfs::StableMemory::default())); 28 | static STABLE_MEMORY: std::cell::RefCell 29 | = std::cell::RefCell::new(icfs::StableMemory::default()); 30 | 31 | static FS: std::cell::RefCell = { 32 | let fs: std::io::Result = STABLE_MEMORY.with(|stable_memory| { 33 | let stable_memory = *stable_memory.borrow(); 34 | 35 | #[cfg(target_arch = "wasm32")] 36 | let memory_pages = core::arch::wasm32::memory_size(0) 37 | .try_into() 38 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error))?; 39 | 40 | #[cfg(not(target_arch = "wasm32"))] 41 | let memory_pages = 19; 42 | 43 | icfs::StableMemory::grow(memory_pages)?; 44 | 45 | // TODO 46 | // let stable_memory = fscommon::BufStream::new(stable_memory); 47 | 48 | fatfs::format_volume( 49 | &mut fatfs::StdIoWrapper::from(stable_memory), 50 | fatfs::FormatVolumeOptions::new(), 51 | )?; 52 | 53 | let options = fatfs::FsOptions::new() 54 | .time_provider(icfs_fatfs::TimeProvider::new()) 55 | .update_accessed_date(true); 56 | 57 | let fs = fatfs::FileSystem::new(stable_memory, options)?; 58 | 59 | Ok(fs) 60 | }); 61 | 62 | std::cell::RefCell::new(fs.unwrap()) 63 | }; 64 | } 65 | 66 | fn open_dir_path<'a>(fs: &'a FileSystem, path: &str) -> std::io::Result> { 67 | let root_dir = fs.root_dir(); 68 | let (base_dir_name, sub_dir_path) = path_head_tail(&path) 69 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error))?; 70 | match (base_dir_name.as_str(), sub_dir_path.as_str()) { 71 | (".", "") => Ok(root_dir), 72 | (".", sub_dir_path) => root_dir 73 | .open_dir(&sub_dir_path) 74 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error)), 75 | _ => Err(std::io::Error::new( 76 | std::io::ErrorKind::Other, 77 | format!("Invalid path: {}", path.to_string()), 78 | )), 79 | } 80 | } 81 | 82 | fn path_head_tail(path: &str) -> Result<(String, String), String> { 83 | let path_segments = path.split("/").collect::>(); 84 | let head = path_segments 85 | .first() 86 | .ok_or(format!("Invalid path: {}", path.to_string()))?; 87 | let tail = path_segments[1..].join("/"); 88 | Ok((head.to_string(), tail)) 89 | } 90 | 91 | fn path_init_last(path: &str) -> Result<(String, String), String> { 92 | let mut path_segments = path.split("/").collect::>(); 93 | let last = path_segments 94 | .pop() 95 | .ok_or(format!("Invalid path: {}", path.to_string()))?; 96 | let init = path_segments.join("/"); 97 | Ok((init, last.to_string())) 98 | } 99 | 100 | #[query] 101 | fn cat(path: String) -> String { 102 | FS.with(|fs| { 103 | let fs = fs.borrow(); 104 | let (dir_path, file_name) = path_init_last(&path) 105 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error))?; 106 | let dir = open_dir_path(&fs, &dir_path)?; 107 | let mut file = dir.open_file(&file_name)?; 108 | let mut buf = vec![]; 109 | file.read_to_end(&mut buf)?; 110 | let contents = String::from_utf8(buf) 111 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error))?; 112 | std::io::Result::Ok(contents) 113 | }) 114 | .unwrap() 115 | } 116 | 117 | #[query] 118 | fn ls(path: String) -> Vec { 119 | FS.with(|fs| { 120 | let fs = fs.borrow(); 121 | let dir = open_dir_path(&fs, &path)?; 122 | let mut entries: std::io::Result> = dir 123 | .iter() 124 | .map(|entry| { 125 | entry 126 | .map(|e| e.file_name()) 127 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error)) 128 | }) 129 | .collect(); 130 | 131 | match entries.as_mut() { 132 | Ok(ok) => ok.sort(), 133 | Err(_err) => (), 134 | } 135 | 136 | entries 137 | }) 138 | .unwrap() 139 | } 140 | 141 | #[update] 142 | fn mkdir(path: String) { 143 | FS.with(|fs| { 144 | let fs = fs.borrow(); 145 | let (dir_path, dir_name) = path_init_last(&path) 146 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error))?; 147 | let dir = open_dir_path(&fs, &dir_path)?; 148 | dir.create_dir(&dir_name)?; 149 | std::io::Result::Ok(()) 150 | }) 151 | .unwrap() 152 | } 153 | 154 | #[update] 155 | fn rm(path: String) { 156 | FS.with(|fs| { 157 | let fs = fs.borrow(); 158 | let (dir_path, target) = path_init_last(&path) 159 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error))?; 160 | let dir = open_dir_path(&fs, &dir_path)?; 161 | dir.remove(&target)?; 162 | std::io::Result::Ok(()) 163 | }) 164 | .unwrap() 165 | } 166 | 167 | #[update] 168 | fn write_file(path: String, contents: String) { 169 | FS.with(|fs| { 170 | let fs = fs.borrow(); 171 | let (dir_path, file_name) = path_init_last(&path) 172 | .map_err(|error| std::io::Error::new(std::io::ErrorKind::Other, error))?; 173 | let dir = open_dir_path(&fs, &dir_path)?; 174 | let mut file = dir.create_file(&file_name)?; 175 | file.truncate()?; 176 | file.write_all(&contents.into_bytes())?; 177 | file.flush()?; 178 | std::io::Result::Ok(()) 179 | }) 180 | .unwrap() 181 | } 182 | -------------------------------------------------------------------------------- /examples/fatfs/test.ic-repl: -------------------------------------------------------------------------------- 1 | import fatfs = "rrkah-fqaaa-aaaaa-aaaaq-cai" as "fatfs.did"; 2 | 3 | let result = call fatfs.ls("."); 4 | assert result == vec {}; 5 | 6 | let result = call fatfs.write_file("./hello.txt", "Hello, World!"); 7 | assert result == null; 8 | 9 | let result = call fatfs.ls("."); 10 | assert result == vec { "hello.txt"; }; 11 | 12 | let result = call fatfs.cat("./hello.txt"); 13 | assert result == "Hello, World!"; 14 | 15 | let result = call fatfs.write_file("./hello.txt", "Hello!"); 16 | assert result == null; 17 | 18 | let result = call fatfs.cat("./hello.txt"); 19 | assert result == "Hello!"; 20 | 21 | let result = call fatfs.write_file("./goodbye.txt", "Goodbye!"); 22 | assert result == null; 23 | 24 | let result = call fatfs.ls("."); 25 | assert result == vec { "goodbye.txt"; "hello.txt" }; 26 | 27 | let result = call fatfs.cat("./goodbye.txt"); 28 | assert result == "Goodbye!"; 29 | 30 | let result = call fatfs.mkdir("./foo"); 31 | assert result == null; 32 | 33 | let result = call fatfs.ls("."); 34 | assert result == vec { "foo"; "goodbye.txt"; "hello.txt" }; 35 | 36 | let result = call fatfs.ls("./foo"); 37 | assert result == vec { "."; ".." }; 38 | 39 | let result = call fatfs.mkdir("./foo/baz"); 40 | assert result == null; 41 | 42 | let result = call fatfs.ls("./foo"); 43 | assert result == vec { "."; ".."; "baz" }; 44 | 45 | let result = call fatfs.write_file("./foo/bar.txt", "bar"); 46 | assert result == null; 47 | 48 | let result = call fatfs.cat("./foo/bar.txt"); 49 | assert result == "bar"; 50 | 51 | let result = call fatfs.ls("./foo"); 52 | assert result == vec { "."; ".."; "bar.txt"; "baz" }; 53 | 54 | let result = call fatfs.rm("./foo/baz"); 55 | assert result == null; 56 | 57 | let result = call fatfs.ls("./foo"); 58 | assert result == vec { "."; ".."; "bar.txt" }; 59 | 60 | let result = call fatfs.rm("./foo/bar.txt"); 61 | assert result == null; 62 | 63 | let result = call fatfs.ls("./foo"); 64 | assert result == vec { "."; ".." }; 65 | 66 | let result = call fatfs.rm("./foo"); 67 | assert result == null; 68 | 69 | let result = call fatfs.ls("."); 70 | assert result == vec { "goodbye.txt"; "hello.txt" }; -------------------------------------------------------------------------------- /examples/icfs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "icfs-example" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Paul Young <84700+paulyoung@users.noreply.github.com>"] 6 | 7 | [lib] 8 | path = "lib.rs" 9 | crate-type = ["cdylib", "lib"] 10 | 11 | [dependencies] 12 | ic-cdk = { git = "https://github.com/dfinity/cdk-rs.git", rev = "a253119adb08929b6304d007ee0a6a37960656ed" } 13 | ic-cdk-macros = "0.3" 14 | icfs = { path = "../../crates/icfs" } -------------------------------------------------------------------------------- /examples/icfs/icfs.did: -------------------------------------------------------------------------------- 1 | service : { 2 | test_writer : () -> (); 3 | test_writer_vectored : () -> (); 4 | test_writer_seek : () -> (); 5 | test_writer_error : () -> (); 6 | test_reader : () -> (); 7 | test_reader_vectored : () -> (); 8 | test_read_to_end : () -> (); 9 | test_read_exact : () -> (); 10 | test_reader_error : () -> (); 11 | test_seek_past_end : () -> (); 12 | test_seek_before_0 : () -> (); 13 | } 14 | -------------------------------------------------------------------------------- /examples/icfs/lib.rs: -------------------------------------------------------------------------------- 1 | // Based on: 2 | // * https://users.rust-lang.org/t/existing-tests-for-read-write-and-seek-traits/72991/2 3 | // * https://github.com/rust-lang/rust/blob/a2ebd5a1f12f4242edf66cbbd471c421bec62753/library/std/src/io/cursor/tests.rs 4 | 5 | #![feature(io_slice_advance)] 6 | #![feature(write_all_vectored)] 7 | 8 | use ic_cdk_macros::{init, query, update}; 9 | use std::io::{IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; 10 | 11 | thread_local! { 12 | static STABLE_MEMORY: std::cell::RefCell 13 | = std::cell::RefCell::new(icfs::StableMemory::default()); 14 | } 15 | 16 | fn setup() { 17 | STABLE_MEMORY.with(|stable_memory| { 18 | let mut stable_memory = *stable_memory.borrow(); 19 | let capacity = icfs::StableMemory::capacity(); 20 | let b: &[_] = &vec![0; capacity]; 21 | 22 | ic_cdk::api::stable::stable64_write(0, &b); 23 | assert_eq!(&icfs::StableMemory::bytes()[..], b); 24 | 25 | stable_memory.seek(SeekFrom::Start(0)).unwrap(); 26 | assert_eq!(stable_memory.stream_position().unwrap(), 0); 27 | }) 28 | } 29 | 30 | #[update] 31 | fn test_writer() { 32 | setup(); 33 | STABLE_MEMORY.with(|stable_memory| { 34 | let mut stable_memory = *stable_memory.borrow(); 35 | assert_eq!(stable_memory.write(&[0]).unwrap(), 1); 36 | assert_eq!(stable_memory.write(&[1, 2, 3]).unwrap(), 3); 37 | assert_eq!(stable_memory.write(&[4, 5, 6, 7]).unwrap(), 4); 38 | stable_memory 39 | .write_all_vectored(&mut [ 40 | IoSlice::new(&[]), 41 | IoSlice::new(&[8, 9]), 42 | IoSlice::new(&[10]), 43 | ]) 44 | .unwrap(); 45 | let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 46 | assert_eq!(&icfs::StableMemory::bytes()[0..11], b); 47 | }) 48 | } 49 | 50 | #[update] 51 | fn test_writer_vectored() { 52 | setup(); 53 | STABLE_MEMORY.with(|stable_memory| { 54 | let mut stable_memory = *stable_memory.borrow(); 55 | assert_eq!(stable_memory.stream_position().unwrap(), 0); 56 | 57 | stable_memory.write_all_vectored(&mut [IoSlice::new(&[0])]).unwrap(); 58 | assert_eq!(stable_memory.stream_position().unwrap(), 1); 59 | 60 | stable_memory.write_all_vectored(&mut [IoSlice::new(&mut [1, 2, 3]), IoSlice::new(&mut [4, 5, 6, 7]),]).unwrap(); 61 | assert_eq!(stable_memory.stream_position().unwrap(), 8); 62 | 63 | stable_memory.write_all_vectored(&mut []).unwrap(); 64 | assert_eq!(stable_memory.stream_position().unwrap(), 8); 65 | 66 | stable_memory.write_all_vectored(&mut [IoSlice::new(&[8, 9])]).unwrap(); 67 | stable_memory.write_all_vectored(&mut [IoSlice::new(&[10])]).unwrap(); 68 | 69 | let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; 70 | assert_eq!(&icfs::StableMemory::bytes()[0..9], b); 71 | }) 72 | } 73 | 74 | #[update] 75 | fn test_writer_seek() { 76 | setup(); 77 | STABLE_MEMORY.with(|stable_memory| { 78 | let mut stable_memory = *stable_memory.borrow(); 79 | 80 | assert_eq!(stable_memory.stream_position().unwrap(), 0); 81 | assert_eq!(stable_memory.write(&[1]).unwrap(), 1); 82 | assert_eq!(stable_memory.stream_position().unwrap(), 1); 83 | 84 | assert_eq!(stable_memory.seek(SeekFrom::Start(2)).unwrap(), 2); 85 | assert_eq!(stable_memory.stream_position().unwrap(), 2); 86 | assert_eq!(stable_memory.write(&[2]).unwrap(), 1); 87 | assert_eq!(stable_memory.stream_position().unwrap(), 3); 88 | 89 | assert_eq!(stable_memory.seek(SeekFrom::Current(-2)).unwrap(), 1); 90 | assert_eq!(stable_memory.stream_position().unwrap(), 1); 91 | assert_eq!(stable_memory.write(&[3]).unwrap(), 1); 92 | assert_eq!(stable_memory.stream_position().unwrap(), 2); 93 | 94 | let capacity = icfs::StableMemory::capacity(); 95 | 96 | assert_eq!(stable_memory.seek(SeekFrom::End(-1)).unwrap(), capacity as u64 - 1); 97 | assert_eq!(stable_memory.stream_position().unwrap(), capacity as u64 - 1); 98 | assert_eq!(stable_memory.write(&[4]).unwrap(), 1); 99 | assert_eq!(stable_memory.stream_position().unwrap(), capacity as u64); 100 | 101 | let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 0]; 102 | assert_eq!(&icfs::StableMemory::bytes()[0..8], b); 103 | 104 | let b: &[_] = &[0, 0, 0, 0, 0, 0, 0, 4]; 105 | assert_eq!(&icfs::StableMemory::bytes()[(capacity - 8)..], b); 106 | }) 107 | } 108 | 109 | #[update] 110 | fn test_writer_error() { 111 | setup(); 112 | STABLE_MEMORY.with(|stable_memory| { 113 | let mut stable_memory = *stable_memory.borrow(); 114 | let capacity = icfs::StableMemory::capacity(); 115 | let offset = capacity as u64 - 2; 116 | assert_eq!(stable_memory.seek(SeekFrom::End(-2)).unwrap(), offset); 117 | assert_eq!(stable_memory.write(&[0]).unwrap(), 1); 118 | assert_eq!(stable_memory.write(&[0, 0]).unwrap(), 1); 119 | assert_eq!(stable_memory.write(&[0, 0]).unwrap(), 0); 120 | }) 121 | } 122 | 123 | #[update] 124 | fn test_reader() { 125 | setup(); 126 | STABLE_MEMORY.with(|stable_memory| { 127 | let mut stable_memory = *stable_memory.borrow(); 128 | stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); 129 | stable_memory.seek(SeekFrom::Start(0)).unwrap(); 130 | 131 | let mut buf = []; 132 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 0); 133 | assert_eq!(stable_memory.stream_position().unwrap(), 0); 134 | 135 | let mut buf = [0]; 136 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 1); 137 | assert_eq!(stable_memory.stream_position().unwrap(), 1); 138 | 139 | let b: &[_] = &[0]; 140 | assert_eq!(buf, b); 141 | 142 | let mut buf = [0; 4]; 143 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 4); 144 | assert_eq!(stable_memory.stream_position().unwrap(), 5); 145 | 146 | let b: &[_] = &[1, 2, 3, 4]; 147 | assert_eq!(buf, b); 148 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 4); 149 | 150 | let b: &[_] = &[5, 6, 7, 0]; 151 | assert_eq!(buf, b); 152 | 153 | let b: &[_] = &[5, 6, 7]; 154 | assert_eq!(&buf[..3], b); 155 | 156 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 4); 157 | let b: &[_] = &[0, 0, 0, 0]; 158 | assert_eq!(buf, b); 159 | }) 160 | } 161 | 162 | // Based on https://github.com/rust-lang/rust/blob/a2af9cf1cf6ccb195eae40cdd793939bc77e7e73/library/std/src/io/mod.rs#L1578 163 | fn read_all_vectored(stable_memory: &mut icfs::StableMemory, mut bufs: &mut [IoSliceMut<'_>]) -> std::io::Result<()> { 164 | // Guarantee that bufs is empty if it contains no data, 165 | // to avoid calling write_vectored if there is no data to be written. 166 | IoSliceMut::advance_slices(&mut bufs, 0); 167 | while !bufs.is_empty() { 168 | match stable_memory.read_vectored(bufs) { 169 | Ok(0) => { 170 | return Err(std::io::Error::new( 171 | std::io::ErrorKind::Other, 172 | "failed to read whole buffer", 173 | )); 174 | } 175 | Ok(n) => IoSliceMut::advance_slices(&mut bufs, n), 176 | Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {} 177 | Err(e) => return Err(e), 178 | } 179 | } 180 | Ok(()) 181 | } 182 | 183 | #[update] 184 | fn test_reader_vectored() { 185 | setup(); 186 | STABLE_MEMORY.with(|stable_memory| { 187 | let mut stable_memory = *stable_memory.borrow(); 188 | stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); 189 | stable_memory.seek(SeekFrom::Start(0)).unwrap(); 190 | 191 | let mut buf = []; 192 | read_all_vectored(&mut stable_memory, &mut [IoSliceMut::new(&mut buf)]).unwrap(); 193 | assert_eq!(stable_memory.stream_position().unwrap(), 0); 194 | 195 | let mut buf = [0]; 196 | read_all_vectored(&mut stable_memory, &mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(); 197 | assert_eq!(stable_memory.stream_position().unwrap(), 1); 198 | 199 | let b: &[_] = &[0]; 200 | assert_eq!(buf, b); 201 | 202 | let mut buf1 = [0; 4]; 203 | let mut buf2 = [0; 4]; 204 | read_all_vectored(&mut stable_memory, &mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),]).unwrap(); 205 | 206 | let b1: &[_] = &[1, 2, 3, 4]; 207 | let b2: &[_] = &[5, 6, 7]; 208 | assert_eq!(buf1, b1); 209 | assert_eq!(&buf2[..3], b2); 210 | 211 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 1); 212 | }) 213 | } 214 | 215 | #[update] 216 | fn test_read_to_end() { 217 | setup(); 218 | STABLE_MEMORY.with(|stable_memory| { 219 | let mut stable_memory = *stable_memory.borrow(); 220 | stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); 221 | stable_memory.seek(SeekFrom::Start(0)).unwrap(); 222 | 223 | let mut v = Vec::new(); 224 | stable_memory.read_to_end(&mut v).unwrap(); 225 | 226 | assert_eq!(v, icfs::StableMemory::bytes()); 227 | }) 228 | } 229 | 230 | #[update] 231 | fn test_read_exact() { 232 | setup(); 233 | STABLE_MEMORY.with(|stable_memory| { 234 | let mut stable_memory = *stable_memory.borrow(); 235 | stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); 236 | stable_memory.seek(SeekFrom::Start(0)).unwrap(); 237 | 238 | let mut buf = []; 239 | assert!(stable_memory.read_exact(&mut buf).is_ok()); 240 | 241 | let mut buf = [8]; 242 | assert!(stable_memory.read_exact(&mut buf).is_ok()); 243 | assert_eq!(buf[0], 0); 244 | 245 | let mut buf = [0, 0, 0, 0, 0, 0, 0]; 246 | assert!(stable_memory.read_exact(&mut buf).is_ok()); 247 | assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]); 248 | }) 249 | } 250 | 251 | #[update] 252 | fn test_reader_error() { 253 | setup(); 254 | STABLE_MEMORY.with(|stable_memory| { 255 | let mut stable_memory = *stable_memory.borrow(); 256 | let capacity = icfs::StableMemory::capacity(); 257 | let offset = capacity as u64 - 2; 258 | assert_eq!(stable_memory.seek(SeekFrom::End(-2)).unwrap(), offset); 259 | 260 | let mut buf = [0]; 261 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 1); 262 | 263 | let mut buf = [0, 0]; 264 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 1); 265 | 266 | let mut buf = [0, 0]; 267 | assert_eq!(stable_memory.read(&mut buf).unwrap(), 0); 268 | }) 269 | } 270 | 271 | #[update] 272 | fn test_seek_past_end() { 273 | setup(); 274 | STABLE_MEMORY.with(|stable_memory| { 275 | let mut stable_memory = *stable_memory.borrow(); 276 | let capacity = icfs::StableMemory::capacity(); 277 | let offset = capacity as u64 + 1; 278 | 279 | assert_eq!(stable_memory.seek(SeekFrom::Start(offset)).unwrap(), offset); 280 | assert!(stable_memory.read(&mut [0]).is_err()); 281 | 282 | assert_eq!(stable_memory.seek(SeekFrom::Start(offset)).unwrap(), offset); 283 | assert!(stable_memory.write(&[3]).is_err()); 284 | }) 285 | } 286 | 287 | #[update] 288 | fn test_seek_before_0() { 289 | setup(); 290 | STABLE_MEMORY.with(|stable_memory| { 291 | let mut stable_memory = *stable_memory.borrow(); 292 | stable_memory.seek(SeekFrom::Start(0)).unwrap(); 293 | assert!(stable_memory.seek(SeekFrom::Current(-1)).is_err()); 294 | 295 | stable_memory.seek(SeekFrom::Start(0)).unwrap(); 296 | let capacity = icfs::StableMemory::capacity(); 297 | let offset = 0 - capacity as i64 - 1; 298 | assert!(stable_memory.seek(SeekFrom::End(offset)).is_err()); 299 | }) 300 | } 301 | -------------------------------------------------------------------------------- /examples/icfs/test.ic-repl: -------------------------------------------------------------------------------- 1 | // Based on: 2 | // * https://users.rust-lang.org/t/existing-tests-for-read-write-and-seek-traits/72991/2 3 | // * https://github.com/rust-lang/rust/blob/a2ebd5a1f12f4242edf66cbbd471c421bec62753/library/std/src/io/cursor/tests.rs 4 | 5 | import icfs = "rrkah-fqaaa-aaaaa-aaaaq-cai" as "icfs.did"; 6 | 7 | let result = call icfs.test_writer(); 8 | assert result == null; 9 | 10 | let result = call icfs.test_writer_vectored(); 11 | assert result == null; 12 | 13 | let result = call icfs.test_writer_seek(); 14 | assert result == null; 15 | 16 | let result = call icfs.test_writer_error(); 17 | assert result == null; 18 | 19 | let result = call icfs.test_reader(); 20 | assert result == null; 21 | 22 | let result = call icfs.test_reader_vectored(); 23 | assert result == null; 24 | 25 | let result = call icfs.test_read_to_end(); 26 | assert result == null; 27 | 28 | let result = call icfs.test_read_exact(); 29 | assert result == null; 30 | 31 | let result = call icfs.test_reader_error(); 32 | assert result == null; 33 | 34 | let result = call icfs.test_seek_past_end(); 35 | assert result == null; 36 | 37 | let result = call icfs.test_seek_before_0(); 38 | assert result == null; 39 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "dfinity-sdk": { 4 | "flake": false, 5 | "locked": { 6 | "lastModified": 1648113953, 7 | "narHash": "sha256-IklA+lDgK67wovqsFLaPpRms8NiI6MGC5c+lZKvPXIs=", 8 | "owner": "paulyoung", 9 | "repo": "nixpkgs-dfinity-sdk", 10 | "rev": "28bb54dc1912cd723dc15f427b67c5309cfe851e", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "owner": "paulyoung", 15 | "repo": "nixpkgs-dfinity-sdk", 16 | "type": "github" 17 | } 18 | }, 19 | "flake-utils": { 20 | "locked": { 21 | "lastModified": 1642700792, 22 | "narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=", 23 | "owner": "numtide", 24 | "repo": "flake-utils", 25 | "rev": "846b2ae0fc4cc943637d3d1def4454213e203cba", 26 | "type": "github" 27 | }, 28 | "original": { 29 | "owner": "numtide", 30 | "repo": "flake-utils", 31 | "type": "github" 32 | } 33 | }, 34 | "ic-repl-src": { 35 | "flake": false, 36 | "locked": { 37 | "lastModified": 1645812852, 38 | "narHash": "sha256-roC87vZmzwiC8q8DZBcN2g+GNXdaccWl60LHLTh8uM8=", 39 | "owner": "chenyan2002", 40 | "repo": "ic-repl", 41 | "rev": "41b561942281533f67299e485c4763f3ce91f787", 42 | "type": "github" 43 | }, 44 | "original": { 45 | "owner": "chenyan2002", 46 | "repo": "ic-repl", 47 | "type": "github" 48 | } 49 | }, 50 | "naersk": { 51 | "inputs": { 52 | "nixpkgs": "nixpkgs" 53 | }, 54 | "locked": { 55 | "lastModified": 1641890987, 56 | "narHash": "sha256-CJOAOlk7mZlBVvUiv9q8SYkK0rjY0UmkWedMI0eajWE=", 57 | "owner": "mhuesch", 58 | "repo": "naersk", 59 | "rev": "193e049d6e4c841faf800e302551d2e0a48eee88", 60 | "type": "github" 61 | }, 62 | "original": { 63 | "owner": "mhuesch", 64 | "repo": "naersk", 65 | "rev": "193e049d6e4c841faf800e302551d2e0a48eee88", 66 | "type": "github" 67 | } 68 | }, 69 | "nixpkgs": { 70 | "locked": { 71 | "lastModified": 1643060704, 72 | "narHash": "sha256-nxJiSJunAdjQXCTsnFbNjlm+sGCPigyNzz1+1rsLDAQ=", 73 | "owner": "NixOS", 74 | "repo": "nixpkgs", 75 | "rev": "68eafd0937d33eda3a88389345da6bb32f2a6d3b", 76 | "type": "github" 77 | }, 78 | "original": { 79 | "id": "nixpkgs", 80 | "type": "indirect" 81 | } 82 | }, 83 | "nixpkgs-mozilla": { 84 | "locked": { 85 | "lastModified": 1645464064, 86 | "narHash": "sha256-YeN4bpPvHkVOpQzb8APTAfE7/R+MFMwJUMkqmfvytSk=", 87 | "owner": "mozilla", 88 | "repo": "nixpkgs-mozilla", 89 | "rev": "15b7a05f20aab51c4ffbefddb1b448e862dccb7d", 90 | "type": "github" 91 | }, 92 | "original": { 93 | "owner": "mozilla", 94 | "repo": "nixpkgs-mozilla", 95 | "type": "github" 96 | } 97 | }, 98 | "nixpkgs_2": { 99 | "locked": { 100 | "lastModified": 1638239011, 101 | "narHash": "sha256-AjhmbT4UBlJWqxY0ea8a6GU2C2HdKUREkG43oRr3TZg=", 102 | "owner": "nixos", 103 | "repo": "nixpkgs", 104 | "rev": "a7ecde854aee5c4c7cd6177f54a99d2c1ff28a31", 105 | "type": "github" 106 | }, 107 | "original": { 108 | "owner": "nixos", 109 | "ref": "21.11", 110 | "repo": "nixpkgs", 111 | "type": "github" 112 | } 113 | }, 114 | "root": { 115 | "inputs": { 116 | "dfinity-sdk": "dfinity-sdk", 117 | "flake-utils": "flake-utils", 118 | "ic-repl-src": "ic-repl-src", 119 | "naersk": "naersk", 120 | "nixpkgs": "nixpkgs_2", 121 | "nixpkgs-mozilla": "nixpkgs-mozilla" 122 | } 123 | } 124 | }, 125 | "root": "root", 126 | "version": 7 127 | } 128 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | dfinity-sdk = { 4 | url = "github:paulyoung/nixpkgs-dfinity-sdk"; 5 | flake = false; 6 | }; 7 | ic-repl-src = { 8 | url = "github:chenyan2002/ic-repl"; 9 | flake = false; 10 | }; 11 | flake-utils.url = "github:numtide/flake-utils"; 12 | 13 | # https://github.com/nix-community/naersk/pull/211 14 | naersk.url = "github:mhuesch/naersk?rev=193e049d6e4c841faf800e302551d2e0a48eee88"; 15 | # naersk.url = "github:nix-community/naersk"; 16 | 17 | nixpkgs.url = "github:nixos/nixpkgs/21.11"; 18 | nixpkgs-mozilla.url = "github:mozilla/nixpkgs-mozilla"; 19 | }; 20 | 21 | outputs = { 22 | self, 23 | nixpkgs, 24 | dfinity-sdk, 25 | flake-utils, 26 | ic-repl-src, 27 | naersk, 28 | nixpkgs-mozilla, 29 | }: 30 | flake-utils.lib.eachDefaultSystem ( 31 | system: let 32 | pkgs = import nixpkgs { 33 | inherit system; 34 | overlays = [ 35 | (final: prev: (import dfinity-sdk) final prev) 36 | ]; 37 | }; 38 | 39 | # Get a specific rust version 40 | mozilla = pkgs.callPackage (nixpkgs-mozilla + "/package-set.nix") {}; 41 | rust = (mozilla.rustChannelOf { 42 | # channel = "1.56.0"; 43 | # sha256 = "L1e0o7azRjOHd0zBa+xkFnxdFulPofTedSTEYZSjj2s="; 44 | channel = "nightly"; 45 | date = "2022-04-07"; # day of 1.60.0 release 46 | sha256 = "z+elrzVPDgtdqSMg8NTSGqkmfsK6vOn9XUFXcsSXhXo="; 47 | # sha256 = pkgs.lib.fakeSha256; 48 | }).rust.override { 49 | extensions = [ 50 | "clippy-preview" 51 | # "miri-preview" 52 | # "rls-preview" 53 | # "rust-analyzer-preview" 54 | "rustfmt-preview" 55 | # "llvm-tools-preview" 56 | # "rust-analysis" 57 | # "rust-std" 58 | # "rustc-dev" 59 | # "rustc-docs" 60 | "rust-src" 61 | ]; 62 | targets = [ 63 | "wasm32-unknown-unknown" 64 | ]; 65 | }; 66 | 67 | # Override the version used in naersk 68 | naersk-lib = naersk.lib."${system}".override { 69 | cargo = rust; 70 | rustc = rust; 71 | }; 72 | 73 | dfinitySdk = (pkgs.dfinity-sdk { 74 | acceptLicenseAgreement = true; 75 | sdkSystem = system; 76 | })."0.8.4"; 77 | 78 | buildRustPackage = name: root: attrs: 79 | let 80 | packageArgs = [ 81 | "--package" name 82 | ]; 83 | in 84 | naersk-lib.buildPackage ({ 85 | inherit root; 86 | compressTarget = true; 87 | copyBins = true; 88 | copyLibs = true; 89 | copyTarget = true; 90 | } // attrs); 91 | 92 | buildLocalRustPackage = name: 93 | let 94 | options = [ 95 | "--package" name 96 | "--target" "wasm32-unknown-unknown" 97 | ]; 98 | in 99 | buildRustPackage name ./. { 100 | cargoBuildOptions = x: x ++ options; 101 | cargoTestOptions = x: x ++ options; 102 | copyBins = false; 103 | } 104 | ; 105 | 106 | ic-repl = 107 | buildRustPackage "ic-repl" ic-repl-src { 108 | buildInputs = [ 109 | pkgs.libiconv 110 | 111 | # https://nixos.wiki/wiki/Rust#Building_the_openssl-sys_crate 112 | pkgs.openssl_1_1 113 | pkgs.pkgconfig 114 | ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ 115 | pkgs.darwin.apple_sdk.frameworks.Security 116 | ]; 117 | }; 118 | 119 | buildExampleTest = name: package: pkgs.runCommand "${name}-example-test" { 120 | buildInputs = [ 121 | dfinitySdk 122 | ic-repl 123 | pkgs.jq 124 | ]; 125 | } '' 126 | trap "dfx stop" EXIT 127 | 128 | HOME=$TMP 129 | cp -R ${package}/. result 130 | mkdir -p examples/${name} 131 | cp -R ${./examples}/${name}/. examples/${name} 132 | 133 | cp ${./dfx.json} dfx.json 134 | jq '.canisters = (.canisters | map_values(.build = "echo"))' dfx.json > new.dfx.json 135 | mv new.dfx.json dfx.json 136 | 137 | dfx start --background --host 127.0.0.1:0 138 | WEBSERVER_PORT=$(cat .dfx/webserver-port) 139 | dfx deploy ${name} --network "http://127.0.0.1:$WEBSERVER_PORT" 140 | ic-repl --replica "http://127.0.0.1:$WEBSERVER_PORT" examples/${name}/test.ic-repl 141 | dfx stop 142 | 143 | touch $out 144 | ''; 145 | 146 | crossPlatformPackages = { 147 | icfs = buildLocalRustPackage "icfs"; 148 | icfs-fatfs = buildLocalRustPackage "icfs-fatfs"; 149 | 150 | icfs-example = buildLocalRustPackage "icfs-example"; 151 | fatfs-example = buildLocalRustPackage "fatfs-example"; 152 | }; 153 | in 154 | rec { 155 | # `nix build` 156 | defaultPackage = pkgs.runCommand "all" { 157 | buildInputs = pkgs.lib.attrValues packages; 158 | } '' 159 | touch $out 160 | ''; 161 | 162 | packages = crossPlatformPackages // pkgs.lib.optionalAttrs pkgs.stdenv.isDarwin { 163 | icfs-example-test = buildExampleTest "icfs" packages.icfs-example; 164 | fatfs-example-test = buildExampleTest "fatfs" packages.fatfs-example; 165 | }; 166 | 167 | # `nix develop` 168 | devShell = pkgs.mkShell { 169 | buildInputs = [ 170 | dfinitySdk 171 | ic-repl 172 | ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ 173 | pkgs.libiconv 174 | ]; 175 | 176 | # supply the specific rust version 177 | nativeBuildInputs = [ rust ]; 178 | }; 179 | } 180 | ); 181 | } 182 | --------------------------------------------------------------------------------