Skip to content
tbex78Public

About

EZFA3FS. An opensource implementation transactional, copy-on-write filesystem for the 32-MiB EZ-Flash Advance III NOR cartridge. FUSE Compatible.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

EZFA3FS

EZFA3FS is an independent filesystem toolkit for the EZ-Flash Advance III cartridge. It does not use the original EZ3 menu, loader, ROM patching, FAT32, or a partition table.

The project provides the ezfa3fs program for the transactional EZFA3FS format.

Application version: 0.56.0. Newly formatted filesystems use experimental format 0.3.0 in the standard layout and 0.4.0 in the slotted direct-boot layout. Older 0.1.0 and 0.2.0 filesystems are no longer supported and must be recreated in a current format before use.

The FUSE/macFUSE and real-cartridge workflow has been exercised with directories, file creation and reading, replacement, deletion, recursive deletion, large GBA ROM copies, garbage collection, compaction, cartridge pullback, verification, and SHA-256 comparison with source files.

Cartridge reads use save-safe two-byte control transfers. By default, before a writable cartridge session initializes the flash writer, EZFA3FS snapshots all four 32-KiB save banks. On clean unmount it restores all four snapshots when the current contents differ and bank 1 starts with the writer marker 00 04. Otherwise it restores a nonzero snapshot only when all four current banks are zero. If neither condition matches, it performs no save-bank writes. Pass --skip-snapshot-restore on card-mount to disable this save-preservation workflow for that mount: no save-safety USB reconnect is requested, no pre-writer save snapshot is captured, and no save snapshot is restored after unmount. Always unmount cleanly before disconnecting the linker.

Build

Requirements are CMake, a C++17 compiler, libusb-1.0, and FUSE when mount support is wanted.

cmake -S . -B build/cmake
cmake --build build/cmake
ctest --test-dir build/cmake --output-on-failure

The binary is build/cmake/ezfa3fs.

Standard image workflow

./build/cmake/ezfa3fs format cartridge.ezfa3fs
./build/cmake/ezfa3fs mkdir cartridge.ezfa3fs documents
./build/cmake/ezfa3fs put cartridge.ezfa3fs test.txt documents/test.txt
./build/cmake/ezfa3fs put-many cartridge.ezfa3fs README.md LICENSE
./build/cmake/ezfa3fs info cartridge.ezfa3fs
./build/cmake/ezfa3fs list cartridge.ezfa3fs
./build/cmake/ezfa3fs verify cartridge.ezfa3fs
./build/cmake/ezfa3fs card-write cartridge.ezfa3fs

put-many imports source files at the image root using their basenames. It allocates and programs one combined contiguous extent, publishes one metadata generation, and writes the 32-MiB host image once.

In the current format, non-empty files up to 16 KiB share validated 64-KiB packed blocks. Larger files keep dedicated contiguous extents, while empty files and directories use no data blocks. A multi-file transaction programs all of its replacement packed blocks and dedicated extents in one combined cartridge operation.

card-write verifies the image, asks for y/N confirmation, then erases, programs, and verifies the complete 32 MiB cartridge. Pass --skip-verification to omit only the final cartridge read-back verification:

./build/cmake/ezfa3fs card-write cartridge.ezfa3fs --skip-verification

Format the cartridge directly without first creating and writing a complete image. The command erases the cartridge, fills all four save banks with 0x00, writes only the required filesystem metadata, and verifies the cleared save banks and metadata:

./build/cmake/ezfa3fs card-format
./build/cmake/ezfa3fs card-format --direct-boot

Mount the cartridge read-only:

mkdir -p mountpoint
./build/cmake/ezfa3fs card-mount mountpoint --foreground

Mount with direct transactional writes:

./build/cmake/ezfa3fs card-mount mountpoint --writable --foreground

By default, each dirty file's final release waits for cartridge programming and readback verification. Finder therefore reports a copy as complete only after its contents are durable. To allow Finder files to enter the one-second multi-file write-back batch, explicitly select relaxed sync:

./build/cmake/ezfa3fs card-mount mountpoint --writable --foreground --relaxed-sync

In relaxed-sync mode, final file release and fsync return after the file enters the host-memory queue, before it is durable on the cartridge. Finder can report the copy complete while terminal programming continues. Wait for programming to finish before disconnecting or force-unmounting the cartridge. Clean unmount still drains and verifies the queue. A crash, forced unmount, process termination, USB removal, or power loss during that interval can lose acknowledged writes. Strict sync remains the default.

Add --verify to either mount mode to verify referenced file data before mounting. A writable mount without --verify reads only the metadata needed to start, which is much faster on cartridges containing large files. Without --verify, card-mount does not run the full referenced-file checksum verification.

For writable mounts, --skip-snapshot-restore disables the normal save-preservation workflow for that mount. EZFA3FS does not request the pre-writer or post-unmount USB reconnect, does not capture the pre-writer save snapshot, and does not restore save memory after unmount. Without this option, the existing snapshot/reconnect/restore behavior is unchanged.

For a faster unmounted import of several files, use one cartridge transaction:

./build/cmake/ezfa3fs card-put-many first.gba notes.txt artwork.bmp

The command uses each source basename as its root-level destination, allocates one combined extent, performs one data-writer preparation, verifies all blocks, and publishes one metadata generation. It retains the normal save snapshot and restoration workflow. Pass --skip-snapshot-restore only when intentionally accepting the same save-memory risk described for writable mounts. An empty direct-boot filesystem must receive its special block-zero ROM through put on an image or through a writable mount before it can accept a normal batch.

Unmount from another terminal with umount mountpoint.

Direct boot

The experimental direct-boot layout places one root-level GBA ROM at cartridge byte offset zero for compatible direct-boot logic in the companion ezfadvanceIII project.

Create it with a ROM:

./build/cmake/ezfa3fs format --direct-boot direct-boot.ezfa3fs rom.gba

Or create an empty image with a one-block provisional boot slot and copy the first ROM through a writable mount later:

./build/cmake/ezfa3fs format --direct-boot direct-boot.ezfa3fs

The first persistent file must be a non-empty root-level .gba file. Its boot slot is resized to exactly the number of 64 KiB blocks required by the ROM. Existing direct-boot filesystems with an oversized legacy slot are normalized from the immutable ROM extent when opened. Additional files and directories live after the resulting boundary, so direct boot remains compatible with a multi-file filesystem without reserving unused ROM capacity.

The ROM at offset zero is immutable while present. Delete it, then copy a new root-level .gba file to replace it. Deletion erases only logical block 0 to invalidate the old ROM immediately. When a replacement is copied, its required stale blocks are erased, the slot is resized to the replacement ROM, and the ROM is programmed in one capture-derived writer session; programmed blocks are then verified before the manifest is committed. Retries resume at the first unverified block. Blocks released by a smaller replacement become reclaimable filesystem space. A direct-boot ROM may occupy at most 510 blocks (31.875 MiB).

Command reference

Image commands:

ezfa3fs format IMAGE.ezfa3fs
ezfa3fs format --direct-boot IMAGE.ezfa3fs [ROM.gba]
ezfa3fs info IMAGE.ezfa3fs
ezfa3fs list IMAGE.ezfa3fs
ezfa3fs verify IMAGE.ezfa3fs
ezfa3fs mkdir IMAGE.ezfa3fs DIRECTORY
ezfa3fs put IMAGE.ezfa3fs SOURCE_FILE [DESTINATION]
ezfa3fs put-many IMAGE.ezfa3fs SOURCE_FILE...
ezfa3fs get IMAGE.ezfa3fs FILE OUTPUT_FILE
ezfa3fs rm IMAGE.ezfa3fs FILE
ezfa3fs rmdir IMAGE.ezfa3fs DIRECTORY
ezfa3fs gc IMAGE.ezfa3fs
ezfa3fs compact IMAGE.ezfa3fs
ezfa3fs space IMAGE.ezfa3fs
ezfa3fs mount IMAGE.ezfa3fs MOUNTPOINT [--writable] [--foreground]

When DESTINATION is omitted from put, the source path is also the destination. put-many places every source at the image root using its basename and rejects duplicate destination basenames.

info reports an image's standard or direct-boot layout, exact on-media format revision, active generation, packed-storage capability, entry count, and active metadata block. card-info reports the same fields directly from a connected cartridge without mounting it, scanning file contents, or changing cartridge data:

./build/cmake/ezfa3fs info cartridge.ezfa3fs
./build/cmake/ezfa3fs card-info

Cartridge commands:

ezfa3fs card-mount MOUNTPOINT --foreground [--verify] [--verbose] [--logfile=PATH]
ezfa3fs card-mount MOUNTPOINT --writable --foreground [--verify] [--verbose] [--logfile=PATH] [--skip-snapshot-restore] [--relaxed-sync]
ezfa3fs card-pull IMAGE.ezfa3fs
ezfa3fs card-format [--direct-boot]
ezfa3fs card-write IMAGE.ezfa3fs [--skip-verification]
ezfa3fs card-put-many SOURCE_FILE... [--skip-snapshot-restore]
ezfa3fs card-info
ezfa3fs card-gc
ezfa3fs card-compact
ezfa3fs card-space

Low-level diagnostics:

ezfa3fs card-read-block BLOCK OUTPUT.bin
ezfa3fs card-erase-plan BLOCK
ezfa3fs card-erase-block BLOCK
ezfa3fs card-program-block BLOCK INPUT.bin

Raw erase and program commands modify cartridge blocks after confirmation. Standard metadata occupies blocks 0 and 1; direct-boot metadata occupies blocks 510 and 511. Using raw commands on metadata or active data can destroy the filesystem.

MacFUSE behavior

Ordinary writes are staged in host memory. In default strict mode, a dirty file's final release programs and verifies it before returning, keeping Finder's completion display aligned with cartridge durability. In relaxed-sync mode, final release instead queues the file for one second of relevant foreground inactivity, allowing adjacent files from a Finder or cp copy to share one extent program, writer activation, verification pass, and metadata generation. Replacement unlinks and macFUSE .fuse_hidden* renames join that deferred transaction instead of interrupting the copy with a namespace-only cartridge commit. Operations requiring the main session lock, including file open and read, postpone the batch so Finder can advance to its next file. Metadata-only getattr, xattr, and statfs traffic does not postpone it indefinitely. flush reports mount health without persisting a partially copied file. In default strict mode, fsync immediately drains the current file and every finalized file already queued. Clean unmount also drains all staged work. An asynchronous programming failure becomes sticky: later mutations fail until the cartridge is remounted, while the previous committed generation remains the recovery point.

Strict mode makes final release and every fsync wait for programming and verification. --relaxed-sync acknowledges both after queueing instead, enabling Finder to stage following files into the same batch. This is an explicit durability tradeoff and is accepted only with a writable cartridge mount. Verbose logs identify releases and fsync as durability=strict or durability=deferred and also trace rename callbacks. Diagnostic timestamps are enabled only when --verbose or --logfile=PATH is supplied. Erasing and programming extent percentages remain visible in the terminal without --verbose; these quiet-mode progress lines have no timestamp. Background garbage-collection start, resume, pause, reclaimed-block, completion, and failure messages are also always visible without timestamps.

Directories are reported as mode 0755 and files as 0644. Unsupported ownership, mode, flag, timestamp-setting, and extended-attribute changes are accepted as compatibility no-ops. Finder .DS_Store and AppleDouble ._* files are held only in memory and disappear on unmount; they do not consume flash.

Do not use macFUSE noappledouble or noapplexattr options. Finder can interpret those rejections as copy failures.

Live cartridge reads retry transient USB failures by reopening the validated writer session and restoring the requested mapping. If a mutation cannot be verified after its retries, the mount rejects subsequent mutations until remounted. The previously committed generation remains the recovery point.

Verify copied data

./build/cmake/ezfa3fs card-pull pulled.ezfa3fs
./build/cmake/ezfa3fs verify pulled.ezfa3fs
./build/cmake/ezfa3fs get pulled.ezfa3fs path/to/rom.gba recovered.gba
shasum -a 256 source.gba recovered.gba

EZFA3FS stores CRC32 values for corruption detection. SHA-256 is calculated externally.

Performance and maintenance

EZFA3FS caches cartridge reads lazily in host memory, up to 32 MiB when every block is touched. Repeated reads and directory access are therefore faster without a full scan during normal mount startup. Disabled FUSE tracing also skips caller command-line lookup and trace formatting; verbose/logfile mounts cache those lookups by process.

For several source files, prefer put-many or card-put-many. The files share one allocation/program transaction and one metadata generation, amortizing the cartridge writer transition that otherwise occurs for each separately committed file. The existing commit() mount boundary also batches all simultaneously staged non-empty files through this same filesystem transaction.

Small files of 16 KiB or less are packed together instead of each reserving a complete 64-KiB block. Replacing a packed file uses copy-on-write: live records from its shared block are validated and written to a new block before the manifest changes. Rename and deletion remain metadata-only, and compaction can combine partially live packed blocks.

NOR operations remain slow: changed blocks are programmed and read back, and metadata is written to the alternate superblock and verified. Hardware failures are retried up to three times. Large copies can take materially longer than ordinary host-filesystem copies.

Inspect capacity and fragmentation with:

./build/cmake/ezfa3fs card-space

It reports active, erased, and unreferenced blocks; potentially available capacity; largest extents; fragmentation; and whether garbage collection is recommended. Run maintenance only while unmounted:

./build/cmake/ezfa3fs card-gc
./build/cmake/ezfa3fs card-compact

Garbage collection erases unreferenced blocks. Compaction relocates active files to form a larger contiguous erased extent. Allocation may invoke maintenance automatically when no suitable extent remains, so keeping erased space available avoids a long pause during a copy.

Mounted background garbage collection ignores metadata-only macOS traffic such as getattr, xattr, and statfs. It scans cooperatively so cartridge-facing requests can interrupt between inspected blocks, then reclaims all stale blocks found by the pass in one erase batch. This amortizes the writer restart and readback transition across the complete batch. The idle interval starts after a foreground cartridge commit finishes; GC never resumes merely because a long file program or verification operation exceeded the idle timeout.

Format references

Current limits

  • Storage is fixed at 32 MiB and files occupy contiguous 64 KiB logical blocks.
  • The format has no FAT compatibility or partition table.
  • Symlinks, hard links, sparse files, persistent permissions, ownership, extended attributes, and Finder metadata are unsupported.
  • Hardware reliability and throughput depend on the EZ-Flash writer, USB connection, and NOR flash.
  • Direct boot is experimental and requires compatible external boot logic.

Disclaimer

Independent project / no affiliation or endorsement

This is an independent, unofficial, community-developed project. It is not affiliated with, associated with, authorized by, endorsed by, sponsored by, supported by, or otherwise connected with Nintendo Co., Ltd., any Nintendo affiliate, the EZ-Flash Team, or any related manufacturer, developer, distributor, or rights holder.

Nintendo, Game Boy Advance, EZ-Flash, EZF Advance III, and any other product names, trademarks, service marks, logos, or brands referenced by this project remain the property of their respective owners. Their use in this repository is solely for identification, compatibility, interoperability, technical documentation, and descriptive purposes and does not imply any affiliation, endorsement, sponsorship, approval, or support.

Neither Nintendo nor the EZ-Flash Team provides support for this project. Questions, bug reports, compatibility issues, device problems, or damage arising from this software should not be directed to Nintendo, the EZ-Flash Team, or their respective affiliates, employees, distributors, or support channels.

Project origin and purpose

This project was started because the original software and drivers for the EZF Advance III are available for and operational with Windows XP, an operating system that is now very old and no longer a practical or desirable platform for many users.

The purpose of this project is therefore to research, document, and develop an independent alternative that can help preserve continued use of existing EZF Advance III hardware on modern Unix-like systems, without requiring the original Windows XP environment. The project is focused on compatibility and interoperability with hardware that users already own; it is not intended to represent, replace, or imply official software, drivers, support, or endorsement from Nintendo or the EZ-Flash Team.

We hope that someone with the necessary technical knowledge and interest will fork this repository and continue the project further. This repository is shared as a working community-developed alternative and as a record of the work already done, in the hope that others may improve, correct, document, and extend it.

This software and project are provided “AS IS” and “AS AVAILABLE,” without warranty of any kind, express or implied.

This project remains under active development and may contain bugs, incomplete features, incorrect assumptions, or unexpected behavior, particularly on hardware and configurations that have not yet been tested. Use of this software may cause data loss, corruption, malfunction, permanent damage, or otherwise render an EZF Advance III device partially or completely unusable (“bricked”).

A substantial portion of this project was created through “vibe coding,” reverse engineering, experimentation, and the use of AI-assisted development tools, including ChatGPT and Codex. As a result, the code may contain errors, inaccurate implementations, undocumented behavior, or functionality that has not been thoroughly tested or independently verified.

The owner of this Git repository does not claim to possess the technical expertise, engineering qualifications, or detailed knowledge necessary to guarantee the correctness or safety of the software. The repository owner may also be unable to provide technical support, debugging assistance, device recovery assistance, repair instructions, or further development support if the software causes problems or damages an EZF Advance III device.

By downloading, installing, modifying, executing, flashing, or otherwise using this software, you acknowledge and accept that you do so entirely at your own risk.

To the maximum extent permitted by applicable law, the author(s), contributor(s), and maintainer(s) of this project shall not be liable for any direct, indirect, incidental, special, consequential, or other damages arising from or related to the use or inability to use this software, including, without limitation, damage to hardware, loss or corruption of data, loss of functionality, device failure, or the permanent bricking of an EZF Advance III device.

You are solely responsible for understanding the risks, making appropriate backups where possible, verifying the software before use, and determining whether you are willing to accept the possibility of permanently damaging your EZF Advance III device.

Do not use this software on any device that you are not prepared to potentially damage or lose. Use this project only if you fully understand and accept these risks.

About

EZFA3FS. An opensource implementation transactional, copy-on-write filesystem for the 32-MiB EZ-Flash Advance III NOR cartridge. FUSE Compatible.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages