nfs4fs 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. nfs4fs-0.1.0/Cargo.toml +11 -0
  2. nfs4fs-0.1.0/PKG-INFO +49 -0
  3. nfs4fs-0.1.0/README.md +34 -0
  4. nfs4fs-0.1.0/nfsv41-sys/Cargo.toml +16 -0
  5. nfs4fs-0.1.0/nfsv41-sys/README.md +117 -0
  6. nfs4fs-0.1.0/nfsv41-sys/build.rs +104 -0
  7. nfs4fs-0.1.0/nfsv41-sys/examples/dbg.rs +68 -0
  8. nfs4fs-0.1.0/nfsv41-sys/src/config.h +9 -0
  9. nfs4fs-0.1.0/nfsv41-sys/src/ganesha_rpc.h +99 -0
  10. nfs4fs-0.1.0/nfsv41-sys/src/lib.rs +18 -0
  11. nfs4fs-0.1.0/nfsv41-sys/src/nfsv41.h +10400 -0
  12. nfs4fs-0.1.0/nfsv41-sys/src/wrapper.c +38 -0
  13. nfs4fs-0.1.0/nfsv41-sys/src/wrapper.h +18 -0
  14. nfs4fs-0.1.0/nfsv41-sys/tests/ops_roundtrip.rs +720 -0
  15. nfs4fs-0.1.0/nfsv41-sys/tests/roundtrip.rs +166 -0
  16. nfs4fs-0.1.0/pyproject.toml +28 -0
  17. nfs4fs-0.1.0/python/.cargo/config.toml +8 -0
  18. nfs4fs-0.1.0/python/.gitignore +7 -0
  19. nfs4fs-0.1.0/python/Cargo.lock +338 -0
  20. nfs4fs-0.1.0/python/Cargo.toml +26 -0
  21. nfs4fs-0.1.0/python/README.md +34 -0
  22. nfs4fs-0.1.0/python/nfs4fs/__init__.py +19 -0
  23. nfs4fs-0.1.0/python/nfs4fs/_fs.py +1114 -0
  24. nfs4fs-0.1.0/python/nfs4fs/_native.pyi +74 -0
  25. nfs4fs-0.1.0/python/nfs4fs/py.typed +1 -0
  26. nfs4fs-0.1.0/python/src/lib.rs +1004 -0
  27. nfs4fs-0.1.0/python/tests/__init__.py +1 -0
  28. nfs4fs-0.1.0/python/tests/common.py +331 -0
  29. nfs4fs-0.1.0/python/tests/conftest.py +41 -0
  30. nfs4fs-0.1.0/python/tests/test_behavior_parity.py +192 -0
  31. nfs4fs-0.1.0/python/tests/test_dummy.py +98 -0
  32. nfs4fs-0.1.0/python/tests/test_fsspec_abstract.py +81 -0
  33. nfs4fs-0.1.0/python/tests/test_nfs_integration.py +152 -0
  34. nfs4fs-0.1.0/python/third_party/libntirpc-sys/Cargo.toml +53 -0
  35. nfs4fs-0.1.0/python/third_party/libntirpc-sys/LICENSE +29 -0
  36. nfs4fs-0.1.0/python/third_party/libntirpc-sys/README.md +66 -0
  37. nfs4fs-0.1.0/python/third_party/libntirpc-sys/build.rs +141 -0
  38. nfs4fs-0.1.0/python/third_party/libntirpc-sys/examples/hello_client.rs +93 -0
  39. nfs4fs-0.1.0/python/third_party/libntirpc-sys/examples/hello_server.rs +181 -0
  40. nfs4fs-0.1.0/python/third_party/libntirpc-sys/src/lib.rs +32 -0
  41. nfs4fs-0.1.0/python/third_party/libntirpc-sys/src/wrapper.h +8 -0
  42. nfs4fs-0.1.0/vnfs/Cargo.toml +16 -0
  43. nfs4fs-0.1.0/vnfs/README.md +57 -0
  44. nfs4fs-0.1.0/vnfs/examples/demo.rs +116 -0
  45. nfs4fs-0.1.0/vnfs/src/client.rs +2608 -0
  46. nfs4fs-0.1.0/vnfs/src/compound.rs +791 -0
  47. nfs4fs-0.1.0/vnfs/src/dummy_vecfs.rs +878 -0
  48. nfs4fs-0.1.0/vnfs/src/error.rs +77 -0
  49. nfs4fs-0.1.0/vnfs/src/lib.rs +26 -0
  50. nfs4fs-0.1.0/vnfs/src/nfs.rs +3069 -0
  51. nfs4fs-0.1.0/vnfs/src/rpc.rs +193 -0
  52. nfs4fs-0.1.0/vnfs/src/session.rs +276 -0
  53. nfs4fs-0.1.0/vnfs/src/vecfs.rs +1840 -0
  54. nfs4fs-0.1.0/vnfs/tests/common/mod.rs +505 -0
  55. nfs4fs-0.1.0/vnfs/tests/dummy_vecfs.rs +90 -0
  56. nfs4fs-0.1.0/vnfs/tests/nfs.rs +1659 -0
@@ -0,0 +1,11 @@
1
+ [workspace]
2
+ members = ["vnfs", "nfsv41-sys"]
3
+ resolver = "2"
4
+
5
+ [workspace.dependencies]
6
+ clap = { version = "4.5.17", features = ["derive"] }
7
+ libc = "0.2"
8
+ libntirpc-sys = "0.2.1"
9
+ nfsv41-sys = { path = "nfsv41-sys", version = "0.1.1" }
10
+ xdr-codec = "0.4.4"
11
+ xdrgen = "0.4.4"
nfs4fs-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: nfs4fs
3
+ Version: 0.1.0
4
+ Requires-Dist: fsspec
5
+ Requires-Dist: black ; extra == 'dev'
6
+ Requires-Dist: pytest ; extra == 'dev'
7
+ Requires-Dist: pytest ; extra == 'test'
8
+ Provides-Extra: dev
9
+ Provides-Extra: test
10
+ Summary: fsspec NFSv4.1 filesystem backed by the vectorized vnfs client
11
+ License: MIT OR Apache-2.0
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
14
+
15
+ # nfs4fs
16
+
17
+ An `fsspec` filesystem (`nfs4://`) backed by the vectorized
18
+ [`vnfs`](../vnfs) NFSv4.1 client.
19
+
20
+ The Rust extension (`nfs4fs._native`) links libntirpc **statically**, so
21
+ `import nfs4fs` works without `LD_LIBRARY_PATH`.
22
+
23
+ ## Build
24
+
25
+ ```sh
26
+ python3 -m venv .venv
27
+ .venv/bin/pip install maturin fsspec pytest
28
+ cd python
29
+ ../.venv/bin/maturin develop
30
+ ```
31
+
32
+ ## Use
33
+
34
+ ```python
35
+ import fsspec
36
+ import nfs4fs # registers the "nfs4" protocol
37
+
38
+ fs = fsspec.filesystem("nfs4", host="127.0.0.1", root="git/some/tree")
39
+ fs.pipe({"nfs4:///a.txt": b"hello", "nfs4:///b.txt": b"world"})
40
+ print(fs.cat(["nfs4:///a.txt", "nfs4:///b.txt"]))
41
+ ```
42
+
43
+ For tests without an NFS server, use `backend="dummy"` (a local-directory
44
+ implementation of the same vectorized API):
45
+
46
+ ```python
47
+ fs = fsspec.filesystem("nfs4", backend="dummy", dummy_root="/tmp/scratch")
48
+ ```
49
+
nfs4fs-0.1.0/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # nfs4fs
2
+
3
+ An `fsspec` filesystem (`nfs4://`) backed by the vectorized
4
+ [`vnfs`](../vnfs) NFSv4.1 client.
5
+
6
+ The Rust extension (`nfs4fs._native`) links libntirpc **statically**, so
7
+ `import nfs4fs` works without `LD_LIBRARY_PATH`.
8
+
9
+ ## Build
10
+
11
+ ```sh
12
+ python3 -m venv .venv
13
+ .venv/bin/pip install maturin fsspec pytest
14
+ cd python
15
+ ../.venv/bin/maturin develop
16
+ ```
17
+
18
+ ## Use
19
+
20
+ ```python
21
+ import fsspec
22
+ import nfs4fs # registers the "nfs4" protocol
23
+
24
+ fs = fsspec.filesystem("nfs4", host="127.0.0.1", root="git/some/tree")
25
+ fs.pipe({"nfs4:///a.txt": b"hello", "nfs4:///b.txt": b"world"})
26
+ print(fs.cat(["nfs4:///a.txt", "nfs4:///b.txt"]))
27
+ ```
28
+
29
+ For tests without an NFS server, use `backend="dummy"` (a local-directory
30
+ implementation of the same vectorized API):
31
+
32
+ ```python
33
+ fs = fsspec.filesystem("nfs4", backend="dummy", dummy_root="/tmp/scratch")
34
+ ```
@@ -0,0 +1,16 @@
1
+ [package]
2
+ name = "nfsv41-sys"
3
+ version = "0.1.2"
4
+ edition = "2024"
5
+ license = "MIT OR Apache-2.0"
6
+ description = "Bindings for the NFSv4.1 protocol structs and XDR codecs (nfsv41.h)"
7
+ repository = "https://github.com/vmingchen/vnfs"
8
+ documentation = "https://docs.rs/nfsv41-sys"
9
+ links = "nfsv41"
10
+ readme = "README.md"
11
+
12
+ [dependencies]
13
+ libntirpc-sys = { workspace = true }
14
+
15
+ [build-dependencies]
16
+ bindgen = "0.72"
@@ -0,0 +1,117 @@
1
+ # nfsv41-sys
2
+
3
+ Raw FFI bindings for the NFSv4.1 protocol, vendored from NFS-Ganesha's
4
+ `nfsv41.h`. This crate provides the protocol data types (`COMPOUND4args`,
5
+ `nfs_argop4`, `nfs_resop4`, ...) and the XDR codecs that encode/decode them,
6
+ as a low-level foundation for the `vnfs` client.
7
+
8
+ This is a `-sys` crate: it exposes unsafe `extern` types and functions with
9
+ manual memory management. Higher-level, safe wrappers live in the `vnfs`
10
+ crate.
11
+
12
+ ## What's in the box
13
+
14
+ | File | Purpose |
15
+ |------|---------|
16
+ | `src/nfsv41.h` | NFS-Ganesha's NFSv4.1 protocol header (structs + static-inline XDR codecs) |
17
+ | `src/wrapper.c` | Five `xdr_wrap_*` extern entry points around the `static inline` codecs (Rust cannot call static-inline functions directly) |
18
+ | `src/wrapper.h` | The bindgen input header (includes `nfsv41.h`, declares the wrappers) |
19
+ | `src/lib.rs` | `include!` of the generated bindings, plus the `-lntirpc` link directive |
20
+ | `build.rs` | Compiles `wrapper.c` into `libnfsv41.a` and runs bindgen |
21
+
22
+ ## Build
23
+
24
+ `build.rs` performs two steps:
25
+
26
+ 1. **C codec archive**: `gcc` compiles `src/wrapper.c` (with libntirpc's
27
+ include directories, supplied by `libntirpc-sys` via its `links`
28
+ metadata as `DEP_NTIRPC_INCLUDE` / `DEP_NTIRPC_INCLUDE2`) into
29
+ `libnfsv41.a`.
30
+ 2. **bindgen**: generates ~15k lines of Rust declarations from
31
+ `src/wrapper.h` into `$OUT_DIR/bindings.rs`, which `src/lib.rs` includes.
32
+
33
+ The archive's object files reference `libntirpc.so` symbols, so the crate
34
+ re-emits `-lntirpc` (and `-lntirpcmonitoring`) at final link time; binaries
35
+ also need `libntirpc.so` on the dynamic linker path at runtime.
36
+
37
+ ## Usage
38
+
39
+ ```rust
40
+ use nfsv41_sys::*;
41
+ use std::os::raw::c_char;
42
+
43
+ unsafe {
44
+ let mut argop: nfs_argop4 = std::mem::zeroed();
45
+ argop.argop = nfs_opnum4_NFS4_OP_PUTFH;
46
+ argop.nfs_argop4_u.opputfh.object.nfs_fh4_len = 4;
47
+ argop.nfs_argop4_u.opputfh.object.nfs_fh4_val = fh.as_ptr() as *mut c_char;
48
+
49
+ let mut args: COMPOUND4args = std::mem::zeroed();
50
+ // ... wire up tag / argarray ...
51
+
52
+ let mut xdr: XDR = std::mem::zeroed();
53
+ xdrmem_ncreate(&mut xdr, buf.as_mut_ptr() as *mut c_char, BUF, xdr_op_XDR_ENCODE);
54
+ xdr_wrap_COMPOUND4args(&mut xdr, &mut args);
55
+ }
56
+ ```
57
+
58
+ ## Tests
59
+
60
+ `tests/roundtrip.rs` encodes a `COMPOUND4args`/`COMPOUND4res` (one PUTFH op)
61
+ with the codecs, decodes it back, and checks the fields match. Run with:
62
+
63
+ ```sh
64
+ cargo test -p nfsv41-sys
65
+ ```
66
+
67
+ ## Improvement roadmap
68
+
69
+ - **Pure-Rust codecs via `xdrgen`.** The workspace already carries
70
+ `protocol/nfsv41.x` (the RFC 5661 XDR spec) and the `xdrgen` /
71
+ `xdr-codec` dependencies. `xdrgen` parses the `.x` spec and emits typed
72
+ `Pack`/`Unpack` implementations, which would remove gcc, `wrapper.c`,
73
+ bindgen, and the `-Wno-incompatible-pointer-types` workaround. See below.
74
+ - **Safe wrapper layer.** Owned buffer types (`Vec<u8>`, `String`), RAII for
75
+ decoded trees (no manual `xdr_free_null_stream`), and safe accessors for
76
+ the `nfs_argop4_u` / `nfs_resop4_u` unions.
77
+ - **Narrow the bindings.** An allowlist of NFS types (instead of blocklists)
78
+ would shrink the generated surface and compile time.
79
+ - **More codec tests.** Round-trips cover PUTFH plus the basic ops
80
+ (READ, WRITE, LOOKUP, READDIR, REMOVE, RENAME, CREATE, GETFH, READLINK,
81
+ GETATTR, COMMIT, LINK) in `tests/ops_roundtrip.rs`; property-based
82
+ round-trips across the remaining ops would catch more XDR bugs.
83
+
84
+ ### How xdrgen generates Rust
85
+
86
+ `xdrgen` (used together with the `xdr-codec` runtime) turns an RFC 4506 /
87
+ RFC 5661 XDR specification into plain Rust source:
88
+
89
+ 1. **Parse.** The XDR grammar is parsed (xdrgen's parser is built on
90
+ `nom`) into an AST of typedefs, structs, unions, enums, constants, and
91
+ program/version blocks.
92
+ 2. **Emit.** The AST is lowered into Rust source text (xdrgen uses `quote`)
93
+ written to `$OUT_DIR/<name>_xdr.rs`. For every type it emits a matching
94
+ `struct` (or `enum` for unions) plus:
95
+ - `impl Pack for T` — the encoder, following the XDR wire rules
96
+ (4-byte alignment, variable-length `<>` prefixes, discriminants for
97
+ unions),
98
+ - `impl Unpack for T` — the decoder, allocating owned `Vec`s/`String`s
99
+ as it goes.
100
+ 3. **Wire up.** The generated file is included with
101
+ `include!(concat!(env!("OUT_DIR"), "/nfsv41_xdr.rs"))` inside a module,
102
+ with `xdr-codec` as a dependency. Types the generator can't express
103
+ (e.g. the `%`-passthrough `authsys_parms`) get hand-written
104
+ `Pack`/`Unpack` impls.
105
+
106
+ In a `build.rs` the whole thing is one call:
107
+
108
+ ```rust
109
+ fn main() {
110
+ xdrgen::compile("protocol/nfsv41.x").unwrap();
111
+ }
112
+ ```
113
+
114
+ For NFSv4.1 the practical caveat is that `xdrgen` 0.4.4 is an old crate
115
+ (deps from the `quote` 0.3 / `nom` 3 era); the complex NFSv4.1 unions and
116
+ the `authsys_parms` passthrough may need manual impls, and the generator
117
+ itself may need a build fix before the raw bindings can be retired.
@@ -0,0 +1,104 @@
1
+ use std::env;
2
+ use std::path::PathBuf;
3
+ use std::process::Command;
4
+
5
+ fn main() {
6
+ let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
7
+ let src_dir = manifest_dir.join("src");
8
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
9
+ // The python/ workspace builds a standalone extension and wants libntirpc
10
+ // linked statically (see python/third_party/libntirpc-sys/build.rs). Only
11
+ // that workspace sets VNFS_STATIC_NTIRPC, so the main workspace keeps the
12
+ // historical dynamic-link flags.
13
+ let static_ntirpc = env::var("VNFS_STATIC_NTIRPC").as_deref() == Ok("1");
14
+
15
+ // Include directory provided by libntirpc-sys (via its `links` metadata).
16
+ let ntirpc_inc = env::var("DEP_NTIRPC_INCLUDE")
17
+ .expect("DEP_NTIRPC_INCLUDE not set; libntirpc-sys must be a dependency");
18
+ // The installed config.h includes "ntirpc/version.h", resolvable only
19
+ // from the libntirpc build tree (DEP_NTIRPC_INCLUDE2).
20
+ let ntirpc_build_inc = env::var("DEP_NTIRPC_INCLUDE2").unwrap_or_default();
21
+
22
+ // Compile the wrappers around the nfsv41.h static inline codecs.
23
+ let mut gcc = Command::new("gcc");
24
+ gcc.arg("-c")
25
+ .arg("-O2")
26
+ .arg("-fno-strict-aliasing")
27
+ // Ganesha's codec calls xdr_pointer with `char **` where ntirpc's
28
+ // prototype takes `void **`; GCC 14 turns this constraint violation
29
+ // into an error by default.
30
+ .arg("-Wno-incompatible-pointer-types")
31
+ .arg(format!("-I{}", ntirpc_inc))
32
+ .arg(format!("-I{}", src_dir.display()));
33
+ if !ntirpc_build_inc.is_empty() {
34
+ gcc.arg(format!("-I{}", ntirpc_build_inc));
35
+ }
36
+ let status = gcc
37
+ .arg(src_dir.join("wrapper.c"))
38
+ .arg("-o")
39
+ .arg(out_dir.join("wrapper.o"))
40
+ .status()
41
+ .unwrap();
42
+ assert!(status.success(), "gcc failed to compile wrapper.c");
43
+
44
+ let status = Command::new("ar")
45
+ .arg("rcs")
46
+ .arg(out_dir.join("libnfsv41.a"))
47
+ .arg(out_dir.join("wrapper.o"))
48
+ .status()
49
+ .unwrap();
50
+ assert!(status.success(), "ar failed");
51
+
52
+ println!("cargo:rustc-link-search=native={}", out_dir.display());
53
+ println!("cargo:rustc-link-lib=static=nfsv41");
54
+ if static_ntirpc {
55
+ // wrapper.o (embedded in this crate's rlib) references symbols in
56
+ // libntirpc; resolve them from the static archive.
57
+ println!("cargo:rustc-link-lib=static=ntirpc");
58
+ } else {
59
+ // wrapper.o references symbols in libntirpc.so; re-assert the link so
60
+ // consumers (including this crate's own tests) get the dynamic
61
+ // library linked too.
62
+ println!("cargo:rustc-link-lib=dylib=ntirpc");
63
+ println!("cargo:rustc-link-lib=dylib=ntirpcmonitoring");
64
+ }
65
+ println!("cargo:rerun-if-changed=src/wrapper.c");
66
+ println!("cargo:rerun-if-changed=src/wrapper.h");
67
+ println!("cargo:rerun-if-changed=src/nfsv41.h");
68
+ println!("cargo:rerun-if-changed=src/ganesha_rpc.h");
69
+ println!("cargo:rerun-if-changed=src/config.h");
70
+
71
+ let mut bindgen = bindgen::Builder::default()
72
+ .header(src_dir.join("wrapper.h").to_str().unwrap())
73
+ .clang_arg(format!("-I{}", ntirpc_inc))
74
+ .clang_arg(format!("-I{}", src_dir.display()));
75
+ if !ntirpc_build_inc.is_empty() {
76
+ bindgen = bindgen.clang_arg(format!("-I{}", ntirpc_build_inc));
77
+ }
78
+ bindgen
79
+ .blocklist_type("rpcblist")
80
+ // Following are unsupported because of usage u128
81
+ .blocklist_function("xdr_quadruple")
82
+ .blocklist_function("strtold")
83
+ .blocklist_type("_Float64x")
84
+ .blocklist_function("qecvt_r")
85
+ .blocklist_function("qfcvt_r")
86
+ .blocklist_function("qecvt")
87
+ .blocklist_function("qfcvt")
88
+ .blocklist_function("qgcvt")
89
+ .generate()
90
+ .expect("Unable to generate bindings")
91
+ .write_to_file(out_dir.join("bindings.rs"))
92
+ .expect("Couldn't write bindings!");
93
+
94
+ // Edition 2024 requires extern blocks to be `unsafe`; rewrite the
95
+ // generated ones that bindgen still emits as plain `extern "C" {`,
96
+ // leaving the blocks bindgen already marks `unsafe` untouched.
97
+ let bindings_path = out_dir.join("bindings.rs");
98
+ let generated = std::fs::read_to_string(&bindings_path).expect("read bindings");
99
+ let rewritten = generated
100
+ .replace("unsafe extern \"C\" {", "\u{0}unsafe_extern\u{0}")
101
+ .replace("extern \"C\" {", "unsafe extern \"C\" {")
102
+ .replace("\u{0}unsafe_extern\u{0}", "unsafe extern \"C\" {");
103
+ std::fs::write(&bindings_path, rewritten).expect("rewrite bindings");
104
+ }
@@ -0,0 +1,68 @@
1
+ use nfsv41_sys::*;
2
+ use std::os::raw::c_char;
3
+
4
+ fn main() {
5
+ unsafe {
6
+ let fh: [u8; 4] = [0xde, 0xad, 0xbe, 0xef];
7
+ let tag = b"roundtrip\0".to_vec();
8
+ let mut argop: nfs_argop4 = std::mem::zeroed();
9
+ argop.argop = nfs_opnum4_NFS4_OP_PUTFH;
10
+ argop.nfs_argop4_u.opputfh.object.nfs_fh4_len = fh.len() as u32;
11
+ argop.nfs_argop4_u.opputfh.object.nfs_fh4_val = fh.as_ptr() as *mut c_char;
12
+ let mut args: COMPOUND4args = std::mem::zeroed();
13
+ args.tag.utf8string_len = tag.len() as u32;
14
+ args.tag.utf8string_val = tag.as_ptr() as *mut c_char;
15
+ args.minorversion = 1;
16
+ args.argarray.argarray_len = 1;
17
+ args.argarray.argarray_val = &mut argop as *mut nfs_argop4;
18
+
19
+ let mut xdr: XDR = std::mem::zeroed();
20
+ let mut buf = vec![0u8; 4096];
21
+ xdrmem_ncreate(
22
+ &mut xdr,
23
+ buf.as_mut_ptr() as *mut c_char,
24
+ 4096,
25
+ xdr_op_XDR_ENCODE,
26
+ );
27
+ let ok = xdr_wrap_COMPOUND4args(&mut xdr, &mut args);
28
+ println!("encode ok: {}", ok);
29
+ let len = xdr.x_data.offset_from(xdr.x_v.vio_base) as usize;
30
+ println!("len: {}", len);
31
+ println!("hex: {:02x?}", &buf[0..len]);
32
+
33
+ let mut xdr2: XDR = std::mem::zeroed();
34
+ let mut b2 = buf[0..len].to_vec();
35
+ xdrmem_ncreate(
36
+ &mut xdr2,
37
+ b2.as_mut_ptr() as *mut c_char,
38
+ len as u32,
39
+ xdr_op_XDR_DECODE,
40
+ );
41
+ let mut decoded: COMPOUND4args = std::mem::zeroed();
42
+ let ok2 = xdr_wrap_COMPOUND4args(&mut xdr2, &mut decoded);
43
+ println!("decode ok: {}", ok2);
44
+ if ok2 {
45
+ println!(
46
+ "tag len {}: {}",
47
+ decoded.tag.utf8string_len,
48
+ String::from_utf8_lossy(std::slice::from_raw_parts(
49
+ decoded.tag.utf8string_val as *const u8,
50
+ decoded.tag.utf8string_len as usize
51
+ ))
52
+ );
53
+ println!("minorversion: {}", decoded.minorversion);
54
+ println!("nargs: {}", decoded.argarray.argarray_len);
55
+ let da = &*decoded.argarray.argarray_val;
56
+ println!("argop: {}", da.argop);
57
+ println!("fh len: {}", da.nfs_argop4_u.opputfh.object.nfs_fh4_len);
58
+ println!(
59
+ "fh: {:02x?}",
60
+ std::slice::from_raw_parts(
61
+ da.nfs_argop4_u.opputfh.object.nfs_fh4_val as *const u8,
62
+ da.nfs_argop4_u.opputfh.object.nfs_fh4_len as usize
63
+ )
64
+ );
65
+ xdr_wrap_COMPOUND4args(&raw mut xdr_free_null_stream, &mut decoded);
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Stand-in for NFS-Ganesha's config.h. The real ganesha config.h
3
+ * carries build-time feature flags (_HAVE_GSSAPI etc.); nfsv41.h does
4
+ * not depend on any of them, so an empty config is sufficient here.
5
+ */
6
+ #ifndef CONFIG_H
7
+ #define CONFIG_H
8
+
9
+ #endif /* !CONFIG_H */
@@ -0,0 +1,99 @@
1
+ /*
2
+ * Minimal stand-in for the NFS-Ganesha <ganesha_rpc.h> header that
3
+ * nfsv41.h includes. nfsv41.h only needs the libntirpc RPC/XDR types
4
+ * plus a couple of GSS-related type names; it does not need any of the
5
+ * real Ganesha infrastructure, so this shim deliberately pulls in only
6
+ * the individual libntirpc headers (avoiding <rpc/rpc.h>, which would
7
+ * drag in <gssapi/gssapi.h> via <rpc/auth_gss.h>).
8
+ */
9
+ #ifndef GANESHA_RPC_H
10
+ #define GANESHA_RPC_H
11
+
12
+ #include <stdbool.h>
13
+ #include <stddef.h>
14
+ #include <stdint.h>
15
+
16
+ #include "config.h"
17
+
18
+ #include <rpc/types.h>
19
+ #include <rpc/xdr.h>
20
+ #include <rpc/xdr_inline.h>
21
+ #include <rpc/rpc_msg.h>
22
+ #include <rpc/auth_unix.h>
23
+
24
+ /*
25
+ * Bounded-array limits for the nfsv41.h codecs. The rpcgen-era header
26
+ * that txn-compound vendors passes maxsize = ~0 for every unbounded
27
+ * array; ntirpc's inline xdr_array_decode rejects maxsize with
28
+ * maxsize > UINT_MAX/selem (an overflow guard), so unbounded arrays
29
+ * must be given a finite cap. Values match NFS-Ganesha
30
+ * src/include/gsh_rpc.h.
31
+ */
32
+ #define XDR_ARRAY_MAXLEN 1024
33
+ /* General-attribute opaque cap (matches NFS-Ganesha gsh_rpc.h). */
34
+ #define XDR_BYTES_MAXLEN (1024 * 1024)
35
+ /* READ/WRITE payloads use the I/O cap (XDR_BYTES_MAXLEN_IO upstream) instead
36
+ * of the 1 MiB general cap, so a single data op can carry a whole compound's
37
+ * budget. */
38
+ #define XDR_BYTES_MAXLEN_IO (64 * 1024 * 1024)
39
+ #define XDR_STRING_MAXLEN (8 * 1024)
40
+
41
+ /* RPCSEC_GSS service type, normally from <rpc/auth_gss.h>. */
42
+ typedef enum rpc_gss_svc {
43
+ RPC_GSS_SVC_NONE = 1,
44
+ RPC_GSS_SVC_INTEGRITY = 2,
45
+ RPC_GSS_SVC_PRIVACY = 3
46
+ } rpc_gss_svc_t;
47
+
48
+ /*
49
+ * Only used by the rpcgen-generated freeresult prototypes in nfsv41.h;
50
+ * the struct layout is never referenced, so an opaque forward-declared
51
+ * typedef is sufficient.
52
+ */
53
+ typedef struct __rpc_svcxprt SVCXPRT;
54
+
55
+ /*
56
+ * Only used in the rpcgen-generated cb_* prototypes in nfsv41.h; the
57
+ * struct layout is never referenced, so an opaque forward-declared
58
+ * typedef is sufficient.
59
+ */
60
+ typedef struct rpc_client CLIENT;
61
+
62
+ /*
63
+ * Ganesha's request-lookahead tracking. nfsv41.h's xdr_nfs_argop4 /
64
+ * xdr_nfs_resop4 codecs maintain a nfs_request_lookahead pointed to by
65
+ * XDR.x_public while they walk the arg/res arrays; the fields are never
66
+ * read back in this crate, but they must be defined for the codecs to
67
+ * compile. Values match NFS-Ganesha src/Protocols/nfs4/support/nfsxdr.h.
68
+ */
69
+ #define NFS_LOOKAHEAD_NONE 0x0000
70
+ #define NFS_LOOKAHEAD_MOUNT 0x0001
71
+ #define NFS_LOOKAHEAD_OPEN 0x0002
72
+ #define NFS_LOOKAHEAD_CLOSE 0x0004
73
+ #define NFS_LOOKAHEAD_READ 0x0008
74
+ #define NFS_LOOKAHEAD_WRITE 0x0010
75
+ #define NFS_LOOKAHEAD_COMMIT 0x0020
76
+ #define NFS_LOOKAHEAD_CREATE 0x0040
77
+ #define NFS_LOOKAHEAD_REMOVE 0x0080
78
+ #define NFS_LOOKAHEAD_RENAME 0x0100
79
+ #define NFS_LOOKAHEAD_LOCK 0x0200
80
+ #define NFS_LOOKAHEAD_READDIR 0x0400
81
+ #define NFS_LOOKAHEAD_LAYOUTCOMMIT 0x0040
82
+ #define NFS_LOOKAHEAD_SETATTR 0x0080
83
+ #define NFS_LOOKAHEAD_SETCLIENTID 0x0100
84
+ #define NFS_LOOKAHEAD_SETCLIENTID_CONFIRM 0x0200
85
+ #define NFS_LOOKAHEAD_LOOKUP 0x0400
86
+ #define NFS_LOOKAHEAD_READLINK 0x0800
87
+
88
+ struct nfs_request_lookahead {
89
+ uint32_t flags;
90
+ uint16_t read;
91
+ uint16_t write;
92
+ };
93
+
94
+ #define NFS_LOOKAHEAD_HIGH_LATENCY(lkhd) \
95
+ (((lkhd).flags & (NFS_LOOKAHEAD_READ | NFS_LOOKAHEAD_WRITE | \
96
+ NFS_LOOKAHEAD_COMMIT | NFS_LOOKAHEAD_LAYOUTCOMMIT | \
97
+ NFS_LOOKAHEAD_READDIR)))
98
+
99
+ #endif /* !GANESHA_RPC_H */
@@ -0,0 +1,18 @@
1
+ #![allow(non_upper_case_globals)]
2
+ #![allow(non_camel_case_types)]
3
+ #![allow(non_snake_case)]
4
+ #![allow(clippy::missing_safety_doc)]
5
+ #![allow(unnecessary_transmutes)]
6
+ #![allow(improper_ctypes)]
7
+ #![allow(improper_ctypes_definitions)]
8
+ #![allow(unsafe_op_in_unsafe_fn)]
9
+ #![allow(clippy::ptr_offset_with_cast)]
10
+
11
+ // The codec wrappers in wrapper.c (compiled into this crate's rlib)
12
+ // reference libntirpc.so symbols directly, so any binary that uses this
13
+ // crate must also link the dynamic library. `#[link]` ensures rustc
14
+ // re-emits -lntirpc at final link time whenever this rlib is pulled in.
15
+ #[link(name = "ntirpc", kind = "dylib")]
16
+ unsafe extern "C" {}
17
+
18
+ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));