Short: Lightweight TCP/IP network file server and mounter
Author: Timm S. Mueller, Claude Sonnet
Uploader: tmueller@schulze-mueller.de
Type: comm/tcp
Version: 0.9rc1
Architecture: m68k-amigaos, Unixoid (Linux, FreeBSD, etc.)


Overview
---------------------------------------------------------------------

Fizz is a lightweight TCP/IP network file server and mounter.

No configuration files, no daemons, no encryption, no hassle - just a
single command line program for sharing and mounting directories
ad hoc style.

WARNING: no authentication. Use on trusted LANs only! - a crossover
cable, a home switch, or a VPN, and use the READONLY option when
appropriate.

Currently supported: Amiga, Unixoid (FUSE3 for mounting e.g. on
Linux, FreeBSD)

Fizz goes both ways: You can share and mount - on all supported
platforms, both directions are supported. So of course you can share
an Amiga directory with other Amigas. You can run as many instances
as you like. There is no central server.

Fizz supports Amiga case-insensitive filenames, permission bits and
comments, not only when serving from an Amiga, but from Unix servers
as well. Support (through xattrs) is provided for Linux, FreeBSD and
more, and the capabilities are detected and dynamically negotiated
with clients requesting them.

This software is considered experimental. Feedback welcome.


Requirements
---------------------------------------------------------------------

Amiga:
OS >= v37, bsdsocket.library v4, 68000 CPU
~150k for mounting or sharing a directory

POSIX/FUSE, build requirements:
gcc or clang, FUSE3 library and headers (libfuse3-dev/fuse3-devel),
pkg-config, pthreads. If your OS doesn't support FUSE for mounting,
maybe you can still run the server, which is very portable besides
some special codepaths for xattrs support.


Build and install
---------------------------------------------------------------------

On Amiga, just:

  # copy fizz C:

On Unixoid fizz goes into /usr/local/bin:

  $ gmake all
  $ sudo make install
  
Building for Amiga requires the vbcc toolchain:

  $ make amiga

Use 'make help' to see a list of targets.


Getting started
---------------------------------------------------------------------

Things to keep in mind:

1. Start by sharing an empty directory.

2. Make sure you don't expose a share on a host or network interface
that is reachable from untrusted networks, such as the internet.
Typically it is safe to use behind a home router which is also a NAT
gateway, but make sure that this is the case.

3. Copy the things to share into the shared directory. While clients
have no means to create links inside a share, if YOU place symlinks
in a share, these can be traversed by clients, even if they cannot
resolve them to their actual paths.

4. When there is no need for clients to write to a share, use the
READONLY option, so data can't be devastated, not even by accident.


Usage
---------------------------------------------------------------------

Share a directory:

  $ fizz serve [rootdir] [PORT num] [RO] [IFACE addr]
  Amiga:
  # fizz serve [rootdir] [PORT num] [RO] [IFACE addr] [TZOFFS sec]

  rootdir defaults to the current directory.
  PORT num defaults to 7777. Port keyword is required to change.
  Keyword RO (or --readonly) rejects all write operations.
  IFACE (or --interface) binds to a specific address (e.g. 127.0.0.1).
  If not specified, the server binds to all of a machine's interfaces!
  TZOFFS specifies a timezone offset in seconds (Amiga), see below.
  Keywords are case-insensitive.

  Examples:
  $ fizz serve                        share current directory on port 7777
  $ fizz serve /home/shared           share a specific directory
  # fizz serve RAM:                   share the RAM: disk (Amiga)
  $ fizz serve /srv/pub port 8888     share on a different port
  # fizz serve SYS:T RO               read-only share (Amiga)
  $ fizz serve iface 127.0.0.1        localhost only

Mount a share (client side):

  # fizz mount host[:port] [VOLNAME] [OH] [TZOFFS sec]
  Unix:
  $ fizz mount host[:port] mountpoint [OH] [fuse-options]

  mountpoint must exist and should be an empty directory.
  OH (or --omithidden) hides dot-files from listings (still accessible).

  The client reconnects automatically if the server restarts; operations
  block during reconnect and resume transparently (open files excepted).

  Examples:
  # fizz mount hostname               mounts hostname:7777 to FIZZ: (Amiga)
  # fizz mount hostname NETZ:         mounts hostname:7777 to NETZ: (Amiga)
  $ fizz mount a1200 ~/net -f         mount, running in foreground
  $ fizz mount 192.168.1.5:8888 ~/net
  # fizz mount NEED=nocase server     excplicitely request case-insensitive
                                      names (see below)
  Unmount on Unixoid:
  $ umount ~/net
  $ fusermount3 -u ~/net              if needed (I don't)

  Unmount on Amiga:
  press CTRL-C or send a break signal.
  
Capability management:

  The protocols and defaults are adjusted in such way that things
  "just work", hopefully. For more insight and control over your
  mounted filesystems, show a server's protocol and capabilities:
  
  # fizz query hostname
  
  With the arguments USE and NEED (or --use and --need) you can
  request server capabilities opportunistically or strictly:
  
  USE=nocase would use a server's 'nocase' capability for
  case-insensitive names - if a server can provide that.
  
  The same with NEED=nocase, but mounting would fail if the server
  cannot provide 'nocase' explicitely.
  
  Amiga servers provide (and Amiga clients by default 'use')
  "iso-8859-1,amiga-case,amiga-comment,amiga-flags".
  
  Unix servers offer "unix,case,amiga-case", and additionally 
  "amiga-comment,amiga-flags" if xattrs support can be provided.
  Unix clients by default use "unix,case".
  
  So, by default, Amiga clients get case-insensitive names, Amiga
  comments and permissions even from Unix servers, provided that
  the server's OS and filesystem support xattrs.
  
  Unix servers and clients talk to each other in a pretty standard
  unix-ish way, except for that chown and chgrp are supported by the
  protocol - as Fizz is expected to run under user permissions and
  without privilege changes. 
  

More Amiga-specific notes
---------------------------------------------------------------------

- A good place for setting up shares on an Amiga is in
AmiTCP:db/user-startnet, e.g.:

run <>NIL: fizz mount hostname SHARE: tzoffs 7200

With this method shares can come up and go away by starting and
stopping the network.
 
- For correct datestamps on Amiga, use the TZOFFS argument to
normalize your time towards UTC. The server always carries
timestamps in UTC. The offset is specified in seconds. If your
Amiga is running in CEST, local time, in summer, you would specify
TZOFFS 7200 for both clients and servers running on this Amiga.
Ideally you get the system time per NTP sync, and calculate TZOFFS
with some help from TZUtil or similar.

- On the Amiga client side, use the experimental option LOCKING/S to
enable full file-lock semantics locally, per client mount. No locking
goes over the wire protocol and so isn't enforced between remote
clients yet, only between applications on the same Amiga.

- Remember that you will probably want to include xattrs for backups
and copies of Amiga directories on a Unix server (cp, rsync, tar).


Disclaimer
---------------------------------------------------------------------

See also COPYRIGHT.

This software was created under the influence of drugs and alcohol.
The only thing that can be guaranteed is that it can corrupt your
data, silently, when you least expect it.
It hasn't been sufficiently tested yet. For more details, see the
Limitations section and the files SECURITY, DESIGN, and TODO.
(However these documents can be erroneous and misleading, too.)

Short version: Consider everything here experimental, and don't
entrust it important data that you cannot recover.


Rationale
---------------------------------------------------------------------

Created for lack of a better tool.

Samba: The smbfs mounter on Amiga is great. But the Samba server is a
pile of bloat and obsolescence, and a nuisance to configure. You are
building megabytes of cruft, and then try to make sense of weird
compatibility options to disable 95% of that. And you keep wondering
when your distribution will finally drop them for godawful security -
which you couldn't care less about in your home network.

NFS: ch_nfsmount on Amiga is great. NFSv2 is fast and easy to setup -
for the 1993 Unix aficionado. In the kernel you enable options nobody
has bothered to switch on in a decade or two. The NFSv2 userland
support, which any sane distribution has abandoned a long time ago,
you build yourself from sources you picked up in a back-alley
scrapyard on the internet. After that it's awesome.

I admit I haven't tried many newer mounters (NFSv3, possibly some 
other for Samba). What I've seen was that I had to write mountlist
entries again, so shares cannot be terminated by the break signal,
and the network stack cannot remove them automatically. And then it
still doesn't work the other way round - and setting up a Samba or
NFS server on an Amiga would be even more insane.

In my opinion, ch_nfsmount and smbfs show how it's done: They are not
handlers that go into L:, but are started as regular programs that
provide the volumes dynamically, and so go away on arrival of the
break signal. That way starting/stopping the network can bring up and
remove shares naturally and cleanly.

These were the reasons why I wanted to write such a thing for a long
time. Now with the arrival of some modern programming languages
(English) and methods (betreutes Coden) I found a good reason to give
these things a try and craft it in exactly the way I wanted.

The result is an Amiga binary about 50k in size which is both server
and client, and works swiftly and nicely even on an Amiga 500. With
it I can not only mount my Unix machines, but even the smallest
Amigas can exchange data between each other. Oh, and you can also use
it for sharing a directory on your laptop in a guest LAN - for you
and your friends to collaborate on some small project. Like, for
example, making an Amiga demo.


Known Limitations
---------------------------------------------------------------------

No authentication
  Any host that can reach the port has full read/write access.
  Use READONLY, --interface and firewall rules when in doubt.

Locking
  Lock() works correctly for normal use: shared locks, directory
  references, Examine, NameFromLock, etc. Full locking semantics
  can be enforced per Amiga mount using the LOCKING option, but it
  is not enforced on the server side and between remote clients yet.

No symlinks or hard links
  The protocol does not support creating symlinks or hard links.
  Existing symlinks on the server appear as NT_LINK entries in
  directory listings; there is no way for clients to resolve their
  targets. File operations (open, readdir) on the server do follow
  symlinks, so a path that crosses a symlink will work if the client
  already knows it - but symlinks pointing outside the share root
  are not blocked. Clients that do not support NT_LINK should skip
  such entries rather than treating them as errors. Directory
  symlinks in the share can cause infinite traversal loops in
  recursive client operations (e.g. recursive copy or backup).

Concurrent truncate + read (AmigaOS server)
  SetFileSize() may be blocked or silently ignored while another
  client has the file open for reading. The server survives; the
  truncation may not take effect.

File sizes > 2 GB (AmigaOS server)
  AmigaOS DOS file offsets are signed 32-bit. The server rejects
  operations beyond 2 GB.

Timestamps (AmigaOS server)
  AmigaOS time resolution is 1/50 second (20 ms). Sub-tick
  precision is lost on round-trips through the Amiga server.
