Default opaque file-handle scheme for NFSv3 backends.
RFC 1813 §2.5 defines nfsfh3 as an opaque variable-length byte
string up to 64 bytes. The handler treats handles as fully opaque
— every interpretation (validation, lookup, refusal) lives in the
backend. Most backends still need some packing, so this module
provides one.
Layout
┌─────────────┬─────────────┬────────────────┬──────────────┐
│ tag (1 B) │ vol_id │ fileid (8 B) │ generation │
│ │ (16 B UUID) │ │ (4 B) │
└─────────────┴─────────────┴────────────────┴──────────────┘
29 bytes total — well under NFS3_FHSIZE = 64- tag —
0x01for "v1 default scheme". Lets future schemes coexist without ambiguity. - vol_id — 16 raw bytes; meant for a UUID, but any 16-byte cluster-stable identifier works.
- fileid — 64-bit big-endian fileid (any persistent inode number or equivalent identifier).
- generation — 32-bit big-endian generation counter; bumped on
delete-and-recreate so a stale handle returns NFS3ERR_STALE
instead of pointing at a different file. Pass
0if the backend doesn't track generations yet.
Wire encoding is just the 29-byte tuple — Tahr.NFSv3.Types.encode_fhandle3/1
wraps it in the variable-opaque XDR envelope.
Backends that want a different scheme
Skip this module entirely and pack whatever you like into the
64-byte budget. The Backend behaviour treats fhandle3() as
binary().
Summary
Functions
Unpack a v1 default-scheme handle. Returns {:error, :badhandle}
for any handle that isn't this scheme — including handles that are
too short, too long, or use a different tag byte. Backends that
pack with a different scheme should not call this function.
Pack {vol_id, fileid, generation} into a v1 default-scheme handle.
The fixed packed-handle byte size for this scheme.
Check whether a decoded handle's vol_id matches the expected
volume. The handler doesn't enforce this — it's a backend
helper for the common case of "refuse a handle that's for a
different volume" with NFS3ERR_STALE.
The tag byte for v1 default-scheme handles.
Types
@type decode_error() :: :stale | :badhandle
Reasons decode/1 may refuse with.
@type decoded() :: %{ vol_id: <<_::128>>, fileid: non_neg_integer(), generation: non_neg_integer() }
Decoded form of a v1 default-scheme handle.
Functions
@spec decode(binary()) :: {:ok, decoded()} | {:error, decode_error()}
Unpack a v1 default-scheme handle. Returns {:error, :badhandle}
for any handle that isn't this scheme — including handles that are
too short, too long, or use a different tag byte. Backends that
pack with a different scheme should not call this function.
@spec encode(<<_::128>>, non_neg_integer(), non_neg_integer()) :: binary()
Pack {vol_id, fileid, generation} into a v1 default-scheme handle.
vol_id must be exactly 16 bytes. fileid and generation are
64-bit and 32-bit unsigned respectively. Raises ArgumentError
on malformed input — every callsite passes already-validated
cluster-internal values.
@spec packed_size() :: 29
The fixed packed-handle byte size for this scheme.
Check whether a decoded handle's vol_id matches the expected
volume. The handler doesn't enforce this — it's a backend
helper for the common case of "refuse a handle that's for a
different volume" with NFS3ERR_STALE.
@spec tag() :: byte()
The tag byte for v1 default-scheme handles.