Skip to content

lex/goafp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

goafp

A modern Apple Filing Protocol (AFP) client in Go, for Linux and macOS.

Apple has deprecated and is removing the AFP client from macOS, leaving Time Capsules and older AFP-only NAS devices unreachable. goafp is a from-scratch replacement informed by the original afpfs-ng C implementation — see this performance analysis of it for why a rewrite: the C client's synchronous, single-request-at-a-time architecture made it an order of magnitude slower than the native client, and fixing that meant rebuilding the core anyway.

Design

  • Pipelined DSI core (internal/dsi): many requests in flight per connection, replies matched to callers by request ID. Concurrency is the default, not a retrofit.
  • Pure-Go protocol layer (internal/afp): AFP 3.x commands and reply parsing, every offset bounds-checked.
  • Portable mounting: goafp mount exposes a volume as a localhost NFSv3 server (internal/nfsfs, a go-billy adapter over the AFP layer) that the OS mounts with its built-in NFS client — mount_nfs on macOS, mount -t nfs on Linux. One codepath for both platforms; no macFUSE kext, no kernel extensions. Metadata operations (chmod, chown, utimes) and statfs map through to AFP.
  • Durable: keepalive tickles stop idle mounts from being dropped, and the bridge transparently reconnects (re-login, re-open volume, re-open file handles) after a server sleep or network blip. Every operation is bounded by a timeout, so a hung server surfaces an error instead of wedging the mount.
  • Testability: protocol logic is exercised against in-process mock servers with fault injection; performance properties are asserted as round-trip counts, not wall-clock times.

Status

Early development, but the read path works end to end against real netatalk (verified in CI-style integration tests, see below).

  • DSI session layer: framing, pipelined request/reply, OpenSession quantum negotiation
  • goafp status — query a server without authenticating
  • Login: guest (No User Authent), DHX2 (Diffie-Hellman + CAST5), and SRP-6a (SHA-1 / MGF1, RFC 5054 group 2)
  • Volume list/open, directory enumeration, stat, UTF-8 path handling
  • File reads with pipelined readahead (concurrent FPReadExt, in-order reassembly)
  • Write path: create, pipelined/coalesced writes, truncate, mkdir, rename/move, delete
  • NFS bridge mounting for Linux + macOS (goafp mount), with chmod/chown/utimes and statfs mapped through to AFP
  • Symlinks (create, readlink, detected in stat/enumerate)
  • netatalk-in-Docker integration test suite (incl. end-to-end NFS and live SRP)
  • Cleartext UAM polish / RandNum UAMs

Usage

go build ./cmd/goafp

# Query any AFP server (Time Capsule, netatalk, old macOS)
./goafp status myserver.local

# List exported volumes (guest, or user:pass@ for authenticated)
./goafp volumes afp://myserver.local
./goafp volumes afp://alice:secret@myserver.local

# List a directory in a volume
./goafp ls afp://alice:secret@myserver.local/Documents
./goafp ls afp://alice:secret@myserver.local/Documents/subdir

# Read a file to stdout, or download it
./goafp cat afp://alice:secret@myserver.local/Documents/notes.txt
./goafp get afp://alice:secret@myserver.local/Documents/archive.zip

# Upload, create directories, rename/move, delete
./goafp put ./report.pdf afp://alice:secret@myserver.local/Documents/report.pdf
./goafp mkdir afp://alice:secret@myserver.local/Documents/2026
./goafp mv    afp://alice:secret@myserver.local/Documents/report.pdf 2026/report.pdf
./goafp rm    afp://alice:secret@myserver.local/Documents/2026/report.pdf

Mounting a volume

goafp mount serves a volume over NFS on localhost; mount it with the OS's built-in NFS client (no kernel extension needed):

# Terminal 1: serve the volume (stays running)
./goafp mount afp://alice:secret@myserver.local/Documents

# Terminal 2: mount it (goafp prints the exact command for your OS)
#   macOS:
sudo mount_nfs -o vers=3,tcp,port=2049,mountport=2049,noowners,resvport \
    127.0.0.1:/ /path/to/mountpoint
#   Linux:
sudo mount -t nfs -o vers=3,tcp,port=2049,mountport=2049,nolock \
    127.0.0.1:/ /path/to/mountpoint

Development

go test ./...          # unit tests (mock DSI/AFP servers, no network)
go vet ./...

Integration tests

test/integration/run.sh spins up netatalk in Docker, seeds a share, and runs the suite against it (requires Docker):

./test/integration/run.sh

License

BSD 3-Clause. See LICENSE.

About

A modern, pipelined Apple Filing Protocol (AFP) client in Go for Linux and macOS — a maintained replacement for the AFP client Apple is removing.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors