CHANGES ----------------------- - Stack usage of the 'query' command was off the charts, corrected - Improved README, synopses, argument names 1.2 - Added automatic service discovery inside the current LAN segment. Requested by aegis. The notation is $ fizz mount :/servicename . - Added ephemeral port mapping service. Now servers can specify a service name with the SERVICE/K argument, and clients can mount with the new notation hostname:/service . This can even coexist with the previous way to explicitly serve and mount by port number, and it doesn't require a protocol change either. Fitz instances negotiate a port-mapping master among each other, and an exiting master transfers this duty to one of the others. The port mapping service runs on port 17710, but if you don't specify SERVICE for a server or don't mount with hostname:/service, Fitz still works without and behaves exactly like before. - dropped GNU-style argument aliases like --readonly and --omithidden, it's all Amiga-ReadArgs()-style now. - Amiga: Fitz is now reetrant and can be made resident (hopefully, I say!) This should save a ton of memory if you are running it multiple times. 1.1 - Amiga client: Added packet types EXAMINE_NEXT, FH_FROM_LOCK, EXAMINE_FH - Amiga client: bug fixed in rename - was too strict on renaming files with held shared lock - unix client under macOS: added FUSE option noappledouble 1.0r1 - Fixed a bug in the memory management, which could let FreeMem(0,0) happen. - Amiga D bit could be misinterpreted with the last protocol change, fixed: A file with D bit unset could not be deleted even with "delete force". - No longer calls AvailMem with MEMF_LARGEST (speed impact should have been small, as this wasn't called frequently) 1.0 - v8 clients and servers now also announce the capability "ino", which allows a mapping between inodes and fib_DiskKey over the wire. All v8 clients and servers, Amiga and Unix, implement it. This should allow tools like GNU Make for Amiga to track filesystem identities even for recursive implicit rules - which is something many filesystems on the Amiga struggle. 1.0rc3 - Breaking the Amiga client could send it to a "reconnect loop" from which there was no exit - hopefully corrected - Amiga client and server now honour an ENV variable TZOFFS. - streamlined build and documentation 1.0rc2 - Amiga client: Added BUFS/N/K argument (default 32768) - Protocol v8 (min v7): reserved opcodes for symlinks (OP_READLINK/SYMLINK), advisory locks (OP_FLOCK), extended attributes (OP_GETXATTR/LISTXATTR/ REMOVEXATTR), and hard links (OP_LINK). New capabilities: symlink, ino, flock, xattr, hardlink. FITZ_STAT_RESP_SIZE_INO=37 (ino+nlink appended to STAT and READDIR entries when FITZ_CAP_INO negotiated). - Unix server: new LINKS/S argument enables symlink capability (FITZ_CAP_SYMLINK); without it the server follows symlinks transparently but does not surface them to clients, replicating previous behavior. - Unix server+client: symlinks implemented (OP_READLINK, OP_SYMLINK); gated on FITZ_CAP_SYMLINK, Unix-Unix only. Amiga clients and servers unaffected. - Unix server+client: advisory flock implemented (OP_FLOCK); gated on FITZ_CAP_FLOCK with FUSE_CAP_FLOCK_LOCKS. Amiga clients and servers unaffected. - Unix server: MODE_OLDFILE upgrade (O_RDONLY -> O_RDWR) is now gated on absence of FITZ_CAP_UNIX, making it Amiga-only as intended. Unix-Unix opens now preserve the requested access mode. - Unix client: chown now returns EPERM instead of silently succeeding. - Unix client: pipelined async writes and read-ahead (WRITE_WINDOW and RA_WINDOW = 8 per open file); errors tracked per file handle and returned on the next write or flush for writes, or immediately for reads. - fitz-test: 7 new Unix-only tests (symlink_basic, symlink_readdir, symlink_follow, symlink_dangling, symlink_to_dir, chown_eperm, flock_basic); 25 tests total on Unix. 1.0rc1 - Major source code cleanup; reduced binary size 1.0pre7 - TZOFFS is auto-negotiated for Amiga clients, also with Amiga servers, assuming that if TZOFFS is not specified for an Amiga server, it's running in the same local time as the connecting Amiga client. The general idea is still that servers run in UTC - except for Amiga servers which were not given the TZOFFS argument. And this cannot fix the lacking notion of DST in Amiga locale, so you will probably want to use TZOFFS anyway when connecting to a Unix server. Unix client now warns when it mounts a local-timezone server, and 'query' reports the negotiated timezone offset. - improved memory management, greatly reduced stacksize especially in amiga server - build fix for Unix server realpath() via define _XOPEN_SOURCE 700 - argparse list macros replaced by proper functions, and list headers now use two NULL nodes, giving correct aliasing for C99 6.5p7 - amiga_client: fix for ACTION_FINDINPUT: now using FITZ_NF_RDONLY - unix client: when decoding stat, returns st_uid, st_gid, blocks and blksize, giving reasonable sizes for du and more useful info. 1.0pre6 - Project renamed from fizz to fitz due to possible name conflict. Please delete C:fizz and fizz-serve, fizz-mount, fizz from /usr/local/bin - Unix now built with -O1 due to possible issue with clang -O2, see Makefile 1.0pre5 - added full support for macOS with macFUSE for mounting. - minor build fixes: no longer depends on GNU make, no longer uses pkgconfig - Server is now _POSIX_C_SOURCE 200809L with a few platform-specific wrappers and #ifdefs. 1.0pre4 - Not all used errnos are POSIX, five errno values differ between Linux and BSD/macOS (ENOTEMPTY, ENAMETOOLONG, EAGAIN, EDEADLK, ENOSYS). These are now encoded as fixed protocol constants (Linux values) at every send/receive boundary, so all platform combinations interoperate correctly. 1.0pre3 - Short: Now registers a device again. Removal of left out icons on the Workbench is now working. Fixed signal handling in server, which could exit the server when clients were still connected. - amiga-client: DLT_DEVICE entry is now always registered alongside the DLT_VOLUME node. Without it Workbench did not poll the fitz device and left-out icons were never put away. - amiga-client: on CTRL-C with open locks, the active lock chain is linked into dol_LockList, dol_Task is nulled on both the volume and device node, and DISKREMOVED is sent via input.device. Workbench responds by scanning left-out icons whose volume has no handler and puts them away, releasing their locks so the handler can exit cleanly. - amiga-client: on connection loss, volume_remove() pulls the volume from the DosList (triggering the "please insert volume" requester) and volume_restore() re-adds it on reconnect, dismissing the requester. - amiga-server: second CTRL-C while waiting for clients now force-quits, consistent with the Unix server. 1.0pre2 - added CIPHER argument to servers. CIPHER used reported in server. - volume node handling (DISKREMOVED/DISKINSERTED) added. 1.0pre1 - Protocol v7 is now the minimum version. All clients and servers should be upgraded. Improved documentation. 0.9r3 - SECRET/K allows to specify a binary blob for the secret up to 1024 bytes - Added BLAKE2-MAC authentication and SPECK64 stream encryption. - Amiga server: Skips redundant Seeks, lazy read buffer allocation - server: writing amiga.flags or amiga.comment xattrs on a file that has no owner-write permission (e.g. FIBF_WRITE set) failed silently with EACCES. Server now temporarily adds S_IWUSR before the xattr loop and restores the original mode afterwards. - amiga-client: when do_rpc() hit a socket error and conn_dead() managed to reconnect, the triggering RPC still returned -EIO, which surfaced as a "not a DOS disk" requester. do_rpc() now retries the full RPC once after a successful reconnect, making server restarts transparent. - added CRC32 option and CTRL-C to amiga-comparetree tool. - Server should now work on MacOSX. Minor fixes in docs and messages 0.9 - Fitz default port changed to 17711 (from 7777) - Amiga: bsdsocket.library version requirement relaxed to v3 (untested), code refactoring and cleanup, server and client free of globals. - protocol v6: dynamic payload negotiation. OP_WRITE ACK extended to written(4) max_payload(4); clients track max_write and chunk writes accordingly. get_max_payload(conn_t *) stub on both servers controls the limit for both reads and writes. Clients start at FITZ_V6_INIT_MAX_WRITE (16KiB) and adjust from ACKs. v6 is a hard requirement: servers reject pre-v6 clients at cap exchange with a descriptive message= key; v6 clients still degrade gracefully when connecting to older servers. - get_max_payload() now also caps OP_READ response size server-side (both servers). Reads silently return fewer bytes than requested when the limit is below the client's maxsize; clients already handle partial reads with follow-up requests. get_max_payload() is now the single knob controlling memory exposure for both transfer directions. - server rejection at cap exchange now includes a message= key with a human-readable reason. New clients print it verbatim; old clients fall back to their existing generic message. Version mismatch and cap-need failure produce distinct messages. Accepted connections log proto vN alongside the negotiated caps. - IFACE got a [:port] option, error is raised if PORT and IFACE mismatch. - Amiga server and client using memory pools. - Amiga DEVNAME argument renamed to VOLNAME. - Amiga server: child processes inherit parent's stack size; should be fine, our stack is pretty lean, only bsdsocket is the unknown - server, fitz-mount: Unix CLI argument parsing rewritten with argparse (Amiga ReadArgs-style templates). Interface structure is now equivalent on both platforms. FUSE pass-through options captured via FUSEARGS/F. - fitz (POSIX shell dispatcher): "query HOST[:PORT]" subcommand added, dispatches to fitz-mount with a dummy mountpoint and QUERY keyword. "version" subcommand prints version from fitz-serve. Clean usage shown on no-argument invocation; "query" with missing host gives a specific error. Version string sourced from binary, not hardcoded. - fitz-mount, amiga-client: cap negotiation rejection now reports the failing constraint. - fitz query / cmd_query now print the negotiated capability set in addition to the server's offer. - reconnect failure suppresses the generic "giving up" message when the failure is a cap rejection (message already printed by try_connect). - capability model simplified: deny= removed from the protocol and all clients/servers (redundant with need= for any real use case, and semantically ambiguous as a connection gate with implicit server-side redirects). nocase (strncasecmp-based, locale-dependent) removed from the Unix server offer. New capability amiga-case: deterministic Latin-1/ASCII case folding; latin1_lower() and latin1_ncasecmp() added to protocol.h. Unix server now offers case and amiga-case only. Amiga server now offers amiga-case only (nocase was redundant there; AmigaOS does the matching). Amiga client defaults to use=amiga-case. Clients support use= and need= only. - Amiga D (Deletable) bit, which is a server extended attribute, should now be honoured in the Amiga client. - assuming no v1/v2 clients are left in the field, pruned some code from clients that refers to pre-v3 protocol - clients, server: more verbose with regard to their offered capabilities and those negotiated when clients connect - Amiga client: improved shutdown path, now reports held locks, tells the user to close applications and put away left out icons on the share - capability management refactored and streamlined into a unified parser - amiga-client: LOCKING: the prefix conflict rule (exclusive lock on a directory blocked all access to entries inside it) was wrong for AmigaDOS semantics. CreateDir() returns an exclusive lock; holding it while copying files into the new directory triggered ERROR_OBJECT_IN_USE for every file open, breaking "copy all clone". Removed the rule; exact and descendant checks remain. - amiga-comparetree: comment_eq treated fib_Comment as a BCPL string (length byte at [0]) but dos.library converts it to a C string before returning from ExNext(), same as fib_FileName. Fixed to use strlen/memcmp from byte 0. - amiga-server: mysnprintf (kprintf.asm) returned strlen+1 instead of strlen (the null character was counted). safe_path used the return value with a `>= outsz` overflow check, which fired when a non-rootcolon path (e.g. "SYS:T/filename") exactly filled the output buffer -- one byte tighter than a volume-root path because of the extra "/" separator. Result: OP_STAT returned EACCES for every file in a shared subdirectory while readdir still worked (the root path "/" never fills the buffer). Fixed by adding `subq.l #1,d0` in kprintf.asm so mysnprintf returns strlen, matching C99 snprintf semantics. - server: amiga-comment and amiga-flags capability added to the Unix server. Comment stored as xattr "amiga.comment" (raw bytes, max 79), flags as "amiga.flags" (1 byte, same bit layout as the wire protocol). Platform wrappers cover Linux (lgetxattr/lsetxattr/lremovexattr, "user." prefix added internally), macOS (getxattr/setxattr/removexattr with XATTR_NOFOLLOW, same "user." prefix), FreeBSD (extattr_get_link/extattr_set_link/ extattr_delete_link with EXTATTR_NAMESPACE_USER, bare name); other platforms compile with silent no-ops. h_setxattr handler added; h_stat and h_readdir append xattr blocks when the client has negotiated the caps. Removing a comment or zeroing flags removes the xattr from the filesystem. At startup the server probes the root directory with a get of a non-existent attribute; if the filesystem returns ENOTSUP/EOPNOTSUPP the xattr caps are silently omitted from the offer so clients never negotiate them. - server: new -v / --verbose flag; logs each xattr get, set, and remove operation to stderr with path, key, return value, and errno. - amiga-comparetree: new standalone Amiga CLI test tool. Takes DIRA/A DIRB/A QUIET/S; walks both trees recursively and compares type, size, DateStamp, protection bits, and fib_Comment for every entry. Reports entries present in only one tree. Returns RETURN_OK (identical), RETURN_WARN (differences found), or RETURN_ERROR (I/O error). Useful for verifying round-trip copies via fitz. - protocol v5: amiga-comment and amiga-flags capabilities. When both sides negotiate amiga-comment, STAT and READDIR responses append an xattr block after the fixed fields. Format: count(1) [klen(1) key(klen) vlen(1) val(vlen)]*count. Key "amiga.comment" carries fib_Comment as raw bytes (max 79). Key "amiga.flags" carries SPAD+H protection bits as one byte, active-high: bit0=delete-protected, bit1=archived, bit2=pure, bit3=script, bit4=hold. OP_SETXATTR (opcode 16) writes xattr entries: xattr_block_len(2) xattr_block path(remaining) -> empty. Amiga server offers amiga-comment and amiga-flags. Amiga client defaults to use=iso-8859-1,nocase,amiga-comment,amiga-flags. ACTION_SET_COMMENT is now forwarded to the server via OP_SETXATTR. amiga-comment and amiga-flags are silently inactive against servers that do not offer them. - protocol v4: capability exchange. Wire: caplen(2,BE) text(caplen), newline-delimited key=value pairs (offer=, need=, use=, deny=, next=start/disconnect). Client sends first; server responds. Server rejects if any cap in client need= is absent from its offer=. Capability names: unix (Unix/POSIX server; real POSIX permission bits including owner/group/other), amiga (AmigaOS server; synthesised permissions, inherently case-insensitive), iso-8859-1 (Latin-1 filenames), case (case-sensitive path matching), nocase (case-insensitive path matching). Unix server offers unix,case,nocase and implements nocase path resolution when requested (nocase_resolve, resolve_last=0 for create/mkdir). Amiga server offers amiga,iso-8859-1,nocase. Clients: USE/NEED/DENY args (Amiga) and --use/--need/--deny options (FUSE); default use=iso-8859-1,nocase,amiga-comment,amiga-flags on Amiga client, use=unix,case on FUSE client (applied when none of use/need/deny are specified). Backward compat: FITZ_PROTO_MIN_VERSION=3; v4/v5 clients connect to v3 servers without cap exchange, falling back to case-sensitive mode. - "fitz query HOST[:PORT]" (Amiga) and "fitz-mount --query HOST[:PORT]" (FUSE): connect, print server's protocol version and offered capabilities, then exit without mounting. - amiga-client: VOLUME_ONLY #ifdef (commented out by default) skips the DLT_DEVICE entry and registers only a DLT_VOLUME, matching ch_nfsmount behaviour. Device name deduplication now applies to both explicit and default names; sequence is FITZ, FITZ2, FITZ3, ... (not FITZ1). - updated systemd service file 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 >= FITZ_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. - fitz-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 "fitz 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. - fitz-mount: --omithidden flag hides dot-files from directory listings while keeping them fully accessible by path. - amiga-client: OMITHIDDEN/S argument to "fitz mount" does the same. - fitz-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. - fitz-serve, amiga-server: client disconnect messages now always printed (previously only during shutdown), including the client IP address. - fitz-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.