CHANGES
-----------------------

0.8
- Unix Signal handling: SIGINT (first) gracefully stops accepting, waits
  for active clients; SIGHUP: same as first SIGINT; SIGTERM forcedly
  exits immediately regardless of active clients; SIGINT (second) same
  as SIGTERM. A self-pipe (g_wakefd) lets the forced path wake the
  pthread_cond_timedwait in the shutdown loop immediately rather than
  waiting up to 5 seconds for the next poll cycle. The wakeup_thread
  reads one byte from the pipe and signals the condvar (all signal
  handlers are async-signal-safe (write to a pipe is POSIX safe))
- added systemv and systemd init scripts and configs in etc/
- extended test suite
- some reformatting, Amiga client refactored to use no globals,
  smaller binary despite extended functionality
- Amiga client dirbuf (per NetLock) no longer capped to a constant, but
  to a fraction of the available memory. (currently this is merely for
  directory traversal, buffer goes away with its dirlock).
- protocol v3 now supports OP_STATFS; amiga client: some heuristic to
  scale blocksize and blocks on large drives into somewhat useful range
- SO_KEEPALIVE added to servers
- Amiga client: Added experimental LOCKING option, to enforce full Amiga
  locking semantics locally, per client instance. No locking goes over
  the wire protocol and so isn't enforced between remote clients yet.
- amiga-client: NetLock.path and OpenFile.path are now heap-allocated
  (trailing bytes of the same AllocVec block as the struct) instead of
  fixed char[512] arrays. Removes the 512-byte path cap and eliminates
  the wasted space for short paths. A global PATHBUF_SIZE (4096) scratch
  buffer (g_pathbuf, heap-allocated at mount time) replaces all per-call
  stack path buffers. Request payload buffers sized to the actual path
  length instead of the former fixed MAX_PATH upper bound.
- amiga-server, server: per-connection file handle table is now a
  heap-allocated array starting at 8 slots, doubled on exhaustion.
  Removes the hard MAX_FH=64 cap; the OS file descriptor limit becomes
  the effective ceiling, with EMFILE returned when that is reached.
- amiga-server: per-handler path buffers (path + safe_path output) are
  now heap-allocated to the actual payload length instead of fixed
  char[512] stack arrays. Removes the 512-byte path cap from all server
  ops (stat, readdir, open, create, mkdir, unlink, rename, truncate,
  chmod, setmtime).

0.7
- protocol: version bumped to 2. Clients now accept server_version >=
  FIZZ_PROTO_VERSION instead of requiring an exact match. This allows
  future additive versions without breaking already-deployed clients
- protocol: new OP_CHMOD (opcode 13). Wire format: mode(4) path -> empty.
- all: partial permission mapping between Unix mode bits and AmigaDOS
  fib_Protection bits. Owner r/w/x are mapped via FIBF_READ/WRITE/EXECUTE
  (all active-low). FIBF_DELETE is always left clear (deletable); group
  and other Unix bits are not mapped. Details in DESIGN.
- amiga-server: STAT and READDIR now derive mode from fib_Protection
  instead of always sending hardcoded 0755/0644.
- amiga-client: fill_fib() now converts received Unix mode to fib_Protection
  so protection bits are visible in directory listings and Protect command.
- fizz-mount, amiga-client: nfs_chmod()/ACTION_SET_PROTECT now forward to
  the server via OP_CHMOD. Silently accepted (no-op) against v1 servers.
- amiga-client: build_path() fixed for AmigaDOS parent-navigation: a
  leading '/' in a name is resolved as one level up per slash. Fixes
  "cd /", "/foo" paths, and "cd //" (grandparent) in shell and programs.
- amiga-client: build_path() treats a lone '.' component as current
  directory (no-op) so "cd ." works instead of returning an error.
- amiga-server: SetFileSize() returns the new file size on success (not
  DOSTRUE), so the failure check must be < 0, not !result. Using !result
  treated a successful truncate-to-zero (return 0) as an error. Fixed in
  both h_open (NF_TRUNC path) and h_truncate. This caused overwrite and
  trunc_zero to fail when the Amiga server was used as the backend.
- all: new OP_SETMTIME (opcode 14). Wire: mtime_sec(8) path -> empty.
  POSIX server uses utimensat() (atime unchanged). Amiga server uses
  SetFileDate(). FUSE client wires nfs_utimens() (was a no-op). Amiga
  client implements ACTION_SET_DATE via OP_SETMTIME; silently succeeds
  against v1 servers. Timestamps go through the same TZOFFS conversion
  as STAT/READDIR, so copy tools that preserve dates will round-trip
  correctly.
- amiga-client: ACTION_FLUSH now drains the async write pipeline and
  propagates any deferred write error, instead of silently succeeding.
- amiga-client: ACTION_INHIBIT now returns DOSFALSE/ERROR_ACTION_NOT_KNOWN
  instead of DOSTRUE, so callers know the volume cannot be inhibited.
- amiga-server, amiga-client: new TZOFFS/N argument (seconds, signed).
  AmigaDOS datestamps are local time; the protocol carries UTC. Without
  TZOFFS, file timestamps appear off by the TZ+DST difference. Set to
  the same value on both sides (e.g. TZOFFS 7200 for CEST). POSIX
  server and FUSE client are not affected (they work in UTC throughout).
- amiga-client: ACTION_FINDINPUT now requests NF_RDWR from the server
  instead of NF_RDONLY. AmigaOS FFS does not enforce open mode per
  filehandle; software that writes to a FINDINPUT handle (e.g. backup
  tools that re-open an archive to patch the header) worked against the
  Amiga server but failed against the POSIX server with a deferred EBADF
  surfacing at ACTION_END time.

0.6
- FreeBSD build fixes for stricter POSIX_SOURCE, FUSE_CAP_ATOMIC_0_TRUNC 
  not supported (our nfs_truncate implements it anyway)
- unix-client, amiga-client: writes are fire-and-forget; the ACK is
  collected asynchronously while the next write is already in flight.
  Eliminates one full round-trip latency per write on sequential writes.
  flush/fsync drain all in-flight writes and return any deferred error.
- amiga-client: TCP_NODELAY and SO_RCVBUF=256KB set on the socket.
  Default receive buffer (4-8 KB on most stacks) caused repeated TCP
  window stalls when receiving large read responses over fast links.
  Big read throughput gain on A3000/68060 over 100 Mbit/s Ethernet.
- amiga-client: ACTION_EXAMINE_OBJECT on the root lock now returns the
  volume name in fib_FileName. Previously returned empty string, causing
  applications that use NameFromLock to fail to open files on the mount.
- amiga-client: async write pipeline was unbounded; server ACKs (12 bytes
  each) accumulated in the TCP receive buffer without ever being drained
  during pure-write workloads (drain_async_writes is only reached via
  do_rpc, which is not called on a sequential write stream). Once the
  buffer filled the server blocked sending the next ACK, stopped reading
  new data, and the client blocked in send - permanent deadlock at a
  deterministic byte offset. Fixed by capping g_async_inflight at
  ASYNC_WRITE_MAX (4); drain_async_writes is called before sending when
  the limit is reached.
- amiga-client: device name passed to "fizz mount" is now stripped of a
  trailing colon so "DH0:" and "DH0" both work.
- server: h_readdir now silently skips entries whose names contain
  protocol-invalid characters (':', '\', control bytes) or are '.'/'..'.
  Such names appeared in POSIX directory listings as '?????????' because
  getattr rejected them via safe_path(); on the Amiga they appeared
  correctly but were unopenable. Now they are simply not served.
- fizz-mount: --omithidden flag hides dot-files from directory listings
  while keeping them fully accessible by path.
- amiga-client: OMITHIDDEN/S argument to "fizz mount" does the same.
- fizz-mount: automatic reconnect after server disconnect. Retries every
  5 s for up to 60 s; ops block during reconnect and resume transparently.
  Open file handles return EBADF (stale server fh) after reconnect.
  If all retries fail, ops return EIO as before.
- amiga-client: same reconnect behaviour, handled inline in conn_dead()
  using Delay(); the current DOS packet fails with an error, subsequent
  ones resume normally after a successful reconnect.
- fizz-serve, amiga-server: client disconnect messages now always printed
  (previously only during shutdown), including the client IP address.
- fizz-serve, amiga-server: new --interface/INTERFACE option to bind to a
  specific IP address instead of all interfaces. Binding to 127.0.0.1
  restricts access to localhost; binding to an internal NIC address limits
  exposure on multi-homed hosts.
