TODO
-----------------------

- the current test suite is too soft still.
  more and more rigid testing would be nice. some ideas needed.
  even running it against an Amiga takes less than 30 seconds currently.

- locking: implement exclusive open/lock semantics across clients.
  client-side locking (LOCKING/S) is done: full AmigaDOS conflict
  semantics enforced in all three directions (exact, ancestor, descendant).
  all locks, directory creates, deletes, renames and file opens participate
  in the lock table (FINDINPUT as shared, FINDOUTPUT/FINDUPDATE as exclusive).
  cross-client enforcement still deferred (see design below).
  design decisions:
  - no OP_LOCK / OP_UNLOCK opcodes; exclusivity flag on OP_OPEN instead
  - server returns EBUSY immediately on conflict (no blocking/queuing)
  - global in-memory lock table on both servers, mutex-protected
    (Linux: pthread_mutex; Amiga: ObtainSemaphore/ReleaseSemaphore -
    child processes share address space so a global table works)
  - no OS-backed locking on either server: AmigaDOS Lock() blocks with
    no non-blocking variant, so the in-memory table is the only option;
    Linux fcntl backing is a compile-time option at best
  - lock owner is per-filehandle token, not per-connection: multiple
    Amiga apps share one connection, so connection-scoped ownership
    would cause an app to get EBUSY from its own connection
  - server releases all locks for a connection on disconnect, same
    loop as file handle cleanup in handle_conn teardown
  - amiga client: h_locate_object (ACCESS_WRITE) and h_findoutput /
    h_findupdate send NF_EXCLUSIVE; EBUSY maps to ERROR_OBJECT_IN_USE
  - POSIX/FUSE client: pass flag through; server enforces, client is
    otherwise uninvolved

- capability exchange: required for v4 protocol. both sides exchange a list of
  key=value pairs before the first opcode. keys: offer, require. values: named
  capability strings (e.g. amiga-locking, unix-utimens, authv1, ...).
  client sends first, server responds with accepted set. either side may end
  with "next=start" (proceed) or "next=disconnect" (incompatible). server is
  the authority: client offers, server accepts a subset. no echo, no ambiguity.
  for v4: only "next=start" and "next=disconnect" need to work; the rest of the
  vocabulary is in place but no capabilities are mandatory yet. this makes all
  future feature negotiation backward-compatible without another version bump.
