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.
- nfs4fs-0.1.0/Cargo.toml +11 -0
- nfs4fs-0.1.0/PKG-INFO +49 -0
- nfs4fs-0.1.0/README.md +34 -0
- nfs4fs-0.1.0/nfsv41-sys/Cargo.toml +16 -0
- nfs4fs-0.1.0/nfsv41-sys/README.md +117 -0
- nfs4fs-0.1.0/nfsv41-sys/build.rs +104 -0
- nfs4fs-0.1.0/nfsv41-sys/examples/dbg.rs +68 -0
- nfs4fs-0.1.0/nfsv41-sys/src/config.h +9 -0
- nfs4fs-0.1.0/nfsv41-sys/src/ganesha_rpc.h +99 -0
- nfs4fs-0.1.0/nfsv41-sys/src/lib.rs +18 -0
- nfs4fs-0.1.0/nfsv41-sys/src/nfsv41.h +10400 -0
- nfs4fs-0.1.0/nfsv41-sys/src/wrapper.c +38 -0
- nfs4fs-0.1.0/nfsv41-sys/src/wrapper.h +18 -0
- nfs4fs-0.1.0/nfsv41-sys/tests/ops_roundtrip.rs +720 -0
- nfs4fs-0.1.0/nfsv41-sys/tests/roundtrip.rs +166 -0
- nfs4fs-0.1.0/pyproject.toml +28 -0
- nfs4fs-0.1.0/python/.cargo/config.toml +8 -0
- nfs4fs-0.1.0/python/.gitignore +7 -0
- nfs4fs-0.1.0/python/Cargo.lock +338 -0
- nfs4fs-0.1.0/python/Cargo.toml +26 -0
- nfs4fs-0.1.0/python/README.md +34 -0
- nfs4fs-0.1.0/python/nfs4fs/__init__.py +19 -0
- nfs4fs-0.1.0/python/nfs4fs/_fs.py +1114 -0
- nfs4fs-0.1.0/python/nfs4fs/_native.pyi +74 -0
- nfs4fs-0.1.0/python/nfs4fs/py.typed +1 -0
- nfs4fs-0.1.0/python/src/lib.rs +1004 -0
- nfs4fs-0.1.0/python/tests/__init__.py +1 -0
- nfs4fs-0.1.0/python/tests/common.py +331 -0
- nfs4fs-0.1.0/python/tests/conftest.py +41 -0
- nfs4fs-0.1.0/python/tests/test_behavior_parity.py +192 -0
- nfs4fs-0.1.0/python/tests/test_dummy.py +98 -0
- nfs4fs-0.1.0/python/tests/test_fsspec_abstract.py +81 -0
- nfs4fs-0.1.0/python/tests/test_nfs_integration.py +152 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/Cargo.toml +53 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/LICENSE +29 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/README.md +66 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/build.rs +141 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/examples/hello_client.rs +93 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/examples/hello_server.rs +181 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/src/lib.rs +32 -0
- nfs4fs-0.1.0/python/third_party/libntirpc-sys/src/wrapper.h +8 -0
- nfs4fs-0.1.0/vnfs/Cargo.toml +16 -0
- nfs4fs-0.1.0/vnfs/README.md +57 -0
- nfs4fs-0.1.0/vnfs/examples/demo.rs +116 -0
- nfs4fs-0.1.0/vnfs/src/client.rs +2608 -0
- nfs4fs-0.1.0/vnfs/src/compound.rs +791 -0
- nfs4fs-0.1.0/vnfs/src/dummy_vecfs.rs +878 -0
- nfs4fs-0.1.0/vnfs/src/error.rs +77 -0
- nfs4fs-0.1.0/vnfs/src/lib.rs +26 -0
- nfs4fs-0.1.0/vnfs/src/nfs.rs +3069 -0
- nfs4fs-0.1.0/vnfs/src/rpc.rs +193 -0
- nfs4fs-0.1.0/vnfs/src/session.rs +276 -0
- nfs4fs-0.1.0/vnfs/src/vecfs.rs +1840 -0
- nfs4fs-0.1.0/vnfs/tests/common/mod.rs +505 -0
- nfs4fs-0.1.0/vnfs/tests/dummy_vecfs.rs +90 -0
- nfs4fs-0.1.0/vnfs/tests/nfs.rs +1659 -0
nfs4fs-0.1.0/Cargo.toml
ADDED
|
@@ -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"));
|