# wick v0.1.0 - Table of Contents

> A standalone Elixir library for building FUSE userspace filesystems on the BEAM.

## Pages

- [Wick](readme.md)
- [Change Log](changelog.md)
- [LICENSE](license.md)

- Guides
  - [Writing a filesystem](writing-a-filesystem.md)

## Modules

- [Wick](Wick.md): Build FUSE userspace filesystems on the BEAM.
- [Wick.Protocol.Request.BatchForget](Wick.Protocol.Request.BatchForget.md): FUSE_BATCH_FORGET — `fuse_batch_forget_in` (8 bytes) followed by
`count` × `fuse_forget_one` records. Exposed as a list of
`{nodeid, nlookup}` tuples.

- [Wick.Protocol.Request.Create](Wick.Protocol.Request.Create.md): FUSE_CREATE — `fuse_create_in` (16 bytes) + name + NUL.
- [Wick.Protocol.Request.Destroy](Wick.Protocol.Request.Destroy.md): FUSE_DESTROY request — empty body.
- [Wick.Protocol.Request.Fallocate](Wick.Protocol.Request.Fallocate.md): FUSE_FALLOCATE — `fuse_fallocate_in` (32 bytes). Wick doesn't
support sparse pre-allocation, so the session will reply
`-ENOSYS` regardless of the fields; we still parse the body so
decode-time validation works.

- [Wick.Protocol.Request.FileLock](Wick.Protocol.Request.FileLock.md): `fuse_file_lock` (24 bytes) — embedded in `GetLk` / `SetLk`
requests and the matching `GetLkReply`. `start` / `end` are
byte-range bounds (ignored for FLOCK semantics). `type` is one
of 0 (`F_RDLCK`) / 1 (`F_WRLCK`) / 2 (`F_UNLCK`). `pid` is the
requesting process id (kernel fills it for us; we echo it in
GetLk replies).

- [Wick.Protocol.Request.Flush](Wick.Protocol.Request.Flush.md): FUSE_FLUSH — `fuse_flush_in` (24 bytes).
- [Wick.Protocol.Request.Forget](Wick.Protocol.Request.Forget.md): FUSE_FORGET — `fuse_forget_in` (8 bytes).
- [Wick.Protocol.Request.Fsync](Wick.Protocol.Request.Fsync.md): FUSE_FSYNC — `fuse_fsync_in` (16 bytes).
- [Wick.Protocol.Request.FsyncDir](Wick.Protocol.Request.FsyncDir.md): FUSE_FSYNCDIR — same wire layout as `Fsync` (`fuse_fsync_in`,
16 bytes); semantics differ (it flushes the directory's
metadata rather than the file's data).

- [Wick.Protocol.Request.GetAttr](Wick.Protocol.Request.GetAttr.md): FUSE_GETATTR — `fuse_getattr_in` (16 bytes).
- [Wick.Protocol.Request.GetLk](Wick.Protocol.Request.GetLk.md): FUSE_GETLK — `fuse_lk_in` (48 bytes). Probes for a conflicting
byte-range lock. `lk_flags & FUSE_LK_FLOCK` (= 1) is meaningless
for GETLK in POSIX terms — the kernel doesn't issue GETLK for
flock when `FUSE_FLOCK_LOCKS` is advertised; handlers fall back
to F_UNLCK if it ever does.

- [Wick.Protocol.Request.GetXattr](Wick.Protocol.Request.GetXattr.md): FUSE_GETXATTR — `fuse_getxattr_in` (8 bytes) + name + NUL.
- [Wick.Protocol.Request.Init](Wick.Protocol.Request.Init.md): FUSE_INIT request — `fuse_init_in` (16 bytes).
- [Wick.Protocol.Request.Interrupt](Wick.Protocol.Request.Interrupt.md): FUSE_INTERRUPT — `fuse_interrupt_in` (8 bytes). Carries the
`unique` of a previously-issued in-flight request that the
kernel wants to cancel (e.g. because userspace received a
signal during a blocking SETLKW).
- [Wick.Protocol.Request.ListXattr](Wick.Protocol.Request.ListXattr.md): FUSE_LISTXATTR — `fuse_getxattr_in` (8 bytes), no name. The
nodeid in the request header identifies the file. Same size-probe
convention as `GetXattr`.

- [Wick.Protocol.Request.Lookup](Wick.Protocol.Request.Lookup.md): FUSE_LOOKUP request — a NUL-terminated name. The parent directory
is the `nodeid` in the request header.

- [Wick.Protocol.Request.Mkdir](Wick.Protocol.Request.Mkdir.md): FUSE_MKDIR — `fuse_mkdir_in` (8 bytes) + name + NUL.
- [Wick.Protocol.Request.Open](Wick.Protocol.Request.Open.md): FUSE_OPEN — `fuse_open_in` (8 bytes).
- [Wick.Protocol.Request.Read](Wick.Protocol.Request.Read.md): FUSE_READ — `fuse_read_in` (40 bytes).
- [Wick.Protocol.Request.Readdir](Wick.Protocol.Request.Readdir.md): FUSE_READDIR — `fuse_read_in` (40 bytes). Same wire layout as
`Read`, but `offset` is a directory-stream cookie.

- [Wick.Protocol.Request.ReaddirPlus](Wick.Protocol.Request.ReaddirPlus.md): FUSE_READDIRPLUS — same wire layout as `Readdir` (`fuse_read_in`,
40 bytes). The reply layout differs (each entry carries inline
attributes via `fuse_direntplus`).

- [Wick.Protocol.Request.Release](Wick.Protocol.Request.Release.md): FUSE_RELEASE — `fuse_release_in` (24 bytes).
- [Wick.Protocol.Request.RemoveXattr](Wick.Protocol.Request.RemoveXattr.md): FUSE_REMOVEXATTR — name + NUL. Nodeid in header.

- [Wick.Protocol.Request.Rename](Wick.Protocol.Request.Rename.md): FUSE_RENAME (12) — `fuse_rename_in` (8 bytes) with the new parent
`nodeid`, then oldname+NUL, then newname+NUL. The old parent is in
the request header.

- [Wick.Protocol.Request.Rename2](Wick.Protocol.Request.Rename2.md): FUSE_RENAME2 (45) — like RENAME plus a `flags` field.
- [Wick.Protocol.Request.Rmdir](Wick.Protocol.Request.Rmdir.md): FUSE_RMDIR — name + NUL. Parent nodeid in header.
- [Wick.Protocol.Request.SetAttr](Wick.Protocol.Request.SetAttr.md): FUSE_SETATTR — `fuse_setattr_in` (88 bytes).
- [Wick.Protocol.Request.SetLk](Wick.Protocol.Request.SetLk.md): FUSE_SETLK / FUSE_SETLKW — `fuse_lk_in` (48 bytes). The
`lk_flags & FUSE_LK_FLOCK` (= 1) bit distinguishes whole-file
`flock(2)` semantics from POSIX byte-range `fcntl(F_SETLK)`
semantics. The same struct decodes both opcodes; the request
atom (`:setlk` vs `:setlkw`) tells the handler whether to block.

- [Wick.Protocol.Request.SetXattr](Wick.Protocol.Request.SetXattr.md): FUSE_SETXATTR — `fuse_setxattr_in` (8 bytes for v7.31) + name + NUL + value.
- [Wick.Protocol.Request.Statfs](Wick.Protocol.Request.Statfs.md): FUSE_STATFS — empty body.
- [Wick.Protocol.Request.Unlink](Wick.Protocol.Request.Unlink.md): FUSE_UNLINK — name + NUL. Parent nodeid in header.
- [Wick.Protocol.Request.Write](Wick.Protocol.Request.Write.md): FUSE_WRITE — `fuse_write_in` (40 bytes) plus `size` bytes of
payload.

- [Wick.Protocol.Response.AttrReply](Wick.Protocol.Response.AttrReply.md): `fuse_attr_out` (104 bytes) — reply to GETATTR / SETATTR.
- [Wick.Protocol.Response.CreateReply](Wick.Protocol.Response.CreateReply.md): FUSE_CREATE reply — `fuse_entry_out` (128) + `fuse_open_out` (16)
back-to-back. Modelled as a struct with two embedded replies to
make pattern matching at the handler side easier.

- [Wick.Protocol.Response.Dirent](Wick.Protocol.Response.Dirent.md): A single directory entry for READDIR. On the wire this is a
24-byte header (`ino`, `off`, `namelen`, `type`) followed by the
name bytes (no NUL) and 0–7 zero bytes of padding so each record
ends on an 8-byte boundary.

- [Wick.Protocol.Response.DirentPlus](Wick.Protocol.Response.DirentPlus.md): A single READDIRPLUS entry — `fuse_direntplus` on the wire. The
record is a 128-byte `fuse_entry_out` followed by the same 24-byte
dirent header as `Dirent`, the name bytes (no NUL), and 0–7 zero
bytes of padding so each record ends on an 8-byte boundary.
- [Wick.Protocol.Response.Empty](Wick.Protocol.Response.Empty.md): Marker for replies that carry only the 16-byte out-header.
- [Wick.Protocol.Response.Entry](Wick.Protocol.Response.Entry.md): `fuse_entry_out` (128 bytes) — reply to LOOKUP / MKDIR / CREATE
(CREATE also appends an `Open` reply).

- [Wick.Protocol.Response.GetLkReply](Wick.Protocol.Response.GetLkReply.md): `fuse_lk_out` (24 bytes) — reply to GETLK. Carries a
`fuse_file_lock` describing either the conflicting lock that
would have been blocked, or `F_UNLCK` (type=2) when the range
is free. SETLK / SETLKW success replies use `Empty` instead
(header-only).

- [Wick.Protocol.Response.Init](Wick.Protocol.Response.Init.md): FUSE_INIT reply — `fuse_init_out` (64 bytes).
- [Wick.Protocol.Response.Open](Wick.Protocol.Response.Open.md): `fuse_open_out` (16 bytes) — reply to OPEN / OPENDIR.
- [Wick.Protocol.Response.Read](Wick.Protocol.Response.Read.md): FUSE_READ reply — a raw binary, length ≤ requested `size`. Used
verbatim as the response body (no wrapper struct on the wire).

- [Wick.Protocol.Response.Readdir](Wick.Protocol.Response.Readdir.md): READDIR reply — an ordered list of `Dirent` records.
- [Wick.Protocol.Response.ReaddirPlus](Wick.Protocol.Response.ReaddirPlus.md): READDIRPLUS reply — an ordered list of `DirentPlus` records.
- [Wick.Protocol.Response.Statfs](Wick.Protocol.Response.Statfs.md): `fuse_statfs_out` / `fuse_kstatfs` (80 bytes) — reply to STATFS.
- [Wick.Protocol.Response.Write](Wick.Protocol.Response.Write.md): `fuse_write_out` (8 bytes) — reply to WRITE.
- [Wick.Protocol.Response.XattrData](Wick.Protocol.Response.XattrData.md): Reply to a real-fetch `GETXATTR` (request `size` > 0): the value
bytes; or to `LISTXATTR`: the NUL-separated, NUL-terminated list
of attribute names. The kernel rejects this reply with `ERANGE`
if the data exceeds the buffer it allocated based on its prior
probe — handlers are responsible for ensuring `byte_size(data)`
fits within the request's `size` budget.

- [Wick.Protocol.Response.XattrSize](Wick.Protocol.Response.XattrSize.md): Reply to a size-probe `GETXATTR` / `LISTXATTR` (the request's
`size` field was 0). The kernel uses the returned `size` to
allocate a buffer and re-issue the request. Encoded as
`fuse_getxattr_out` (8 bytes).

- Transport
  - [Wick.Fusermount](Wick.Fusermount.md): Mount and unmount FUSE filesystems via the `fusermount3` helper.
  - [Wick.Native](Wick.Native.md): Low-level transport bindings for the Linux FUSE kernel ABI.

- Codec
  - [Wick.Protocol](Wick.Protocol.md): Pure-Elixir codec for the Linux FUSE kernel protocol, targeting
FUSE_KERNEL_VERSION 7.31 (the version exposed by libfuse 3.10+ and
the Linux 5.4+ kernel).
  - [Wick.Protocol.Attr](Wick.Protocol.Attr.md): `fuse_attr` — the 88-byte embedded POSIX-attribute struct used inside
`fuse_entry_out`, `fuse_attr_out`, and a few notification payloads.
  - [Wick.Protocol.InHeader](Wick.Protocol.InHeader.md): `fuse_in_header` — the 40-byte prefix on every request the kernel
sends to userspace.
  - [Wick.Protocol.Request](Wick.Protocol.Request.md): Opcode-specific request structs and `decode/2` dispatcher.
  - [Wick.Protocol.Response](Wick.Protocol.Response.md): Opcode-specific response structs and `encode/1` dispatcher.

