Skip to content

mhadida/afp2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 

Repository files navigation

afp2

Pure-Python AFP 2.x file transfer tool for pulling files off classic Macs (Mac OS 8/9, early OS X).

No modern AFP client supports AFP version 2.x — macOS Finder, gvfs, afpfs-ng all require AFP 3.0+. If you have an old Power Mac or beige G3 with files you need to recover, this tool speaks its language.

Zero dependencies. Python 3.6+ standard library only.

Quick start

# 1. Discover what's running on the Mac
python3 afp2.py probe 192.168.1.74

# 2. Browse interactively and download individual files/folders
python3 afp2.py browse 192.168.1.74 -u "My User"

# 3. Dump entire volumes to disk
python3 afp2.py dump 192.168.1.74 -u "My User" --all
python3 afp2.py dump 192.168.1.74 -u "My User" --volume "Macintosh HD"

Username and password are prompted interactively if not provided via flags. Password prompt is hidden (uses getpass).

Commands

probe

Connects to the AFP server and shows its name, machine type, supported AFP versions, and available authentication methods (UAMs). No login required.

$ python3 afp2.py probe 192.168.1.74

Connected to 192.168.1.74:548

Server name:    PowerMac G4
Machine type:   Macintosh
Flags:          0x0003

AFP versions:   AFP2.2, AFPVersion 2.1, AFPVersion 2.0
UAMs:           Cleartxt passwrd, No User Authent

browse

Interactive directory browser. Navigate folders, view file sizes, download individual files or entire directories.

  Commands: # = enter dir / download file
            a = download all files here
            r = download everything recursively
            .. = go up   q = quit

dump

Download entire volumes. Supports resume — re-run the same command to pick up where a failed transfer left off. Existing files with matching sizes are skipped.

# Interactive volume selection
python3 afp2.py dump 192.168.1.74 -u "My User"

# Dump a specific volume
python3 afp2.py dump 192.168.1.74 -u "My User" --volume "Macintosh HD" -o ./backup

# Dump everything
python3 afp2.py dump 192.168.1.74 -u "My User" --all

How it works

AFP (Apple Filing Protocol) runs over DSI (Data Stream Interface) on TCP port 548. This tool implements just enough of the protocol to authenticate, list directories, and read files:

TCP:548 → DSI transport (16-byte headers, request/response)
        → AFP commands (login, enumerate, open fork, read, close)

Key protocol details:

  • DSI framing: 16-byte header with flags, command, request ID, error code, data length
  • AFP 2.x login: FPLogin has NO pad byte after the command byte (unlike AFP 3.x)
  • Cleartext password UAM: Pascal-string username + alignment pad + 8-byte null-padded password
  • FPEnumerate entries: 2-byte header (size + isdir flag), NOT 4 bytes as some docs suggest
  • Long name offsets: Relative to params start (entry_start + 2), not entry start
  • File names: MacRoman encoded — Python's mac_roman codec handles the conversion
  • Root directory ID: Always 2 in AFP

Quirks and hard-won lessons

These are things we discovered debugging against a real Mac OS 9 Power Mac G4 that aren't well-documented anywhere:

  1. No pad after FPLogin command byte. AFP 3.x adds a pad byte; AFP 2.x does not. Getting this wrong means every login attempt fails with a cryptic error.

  2. Enumerate entry headers are 2 bytes, not 4. The entry size and isdir flag are packed into 2 bytes (uint8 + uint8). Some reference implementations incorrectly use 4-byte headers, which causes the parser to read garbage.

  3. Name offsets are relative to params_start. In FPEnumerate responses, the long name offset field is relative to the start of the entry's parameter data (2 bytes into the entry), not the start of the entry itself.

  4. Volume bitmap constants differ from directory/file bitmaps. VOLBIT_ID = 0x0020 while FBIT_FINFO = 0x0020 — they share numeric values but mean completely different things. Using file bitmap constants when opening a volume will return wrong data.

  5. Connection drops on large files. Mac OS 9's AFP server tends to drop TCP connections during large file transfers. The tool handles this with automatic reconnect and resume from partial downloads.

  6. Locked system files. Files like Desktop DB, Desktop DF, and VM Storage return error -5006 (DenyConflict) because Mac OS 9 has them open. These can't be downloaded while the system is running.

  7. AFP error -5014 (ParamErr) at a consistent offset usually means disk-level corruption on the Mac side. No amount of retrying will fix it.

Known limitations

  • Cleartext passwords only. This tool uses the "Cleartxt passwrd" UAM. Don't use it over untrusted networks.
  • No AFP 3.x support. For AFP 3.x servers, use macOS Finder or other modern clients.
  • No write support. This is a read-only tool — it downloads files but can't upload or modify.
  • 4 GB file size limit. AFP 2.x uses 32-bit file sizes. Files over 4 GB can't be addressed.
  • Some system directories may be empty. Mac OS 9 access control can prevent reading certain folders (Systemmappe, Trash, etc.) even with valid credentials.

License

MIT — see LICENSE.

About

Pure-Python AFP 2.x file transfer tool for legacy Macs (Mac OS 8/9)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages