#hfs #macos

hfsplus

Read-only HFS+ / HFSX filesystem parser

1 unstable release

new 0.2.0 Feb 11, 2026

#4 in #hfs


Used in 2 crates

MIT license

76KB
1.5K SLoC

hfsplus

Cross-platform Rust library for reading Apple HFS+ and HFSX filesystems

Version License: MIT Platform

Parse HFS+ / HFSX volumes from raw disk images on any platform — no kernel drivers or FUSE required.

Pure Rust, zero unsafe — works everywhere Rust compiles.


Why hfsplus?

hfsplus is the only pure-Rust library for reading HFS+ filesystems with B-tree traversal and extent overflow support.

Feature hfsplus hfsplus-rs hfs-rs
HFS+
HFSX (case-sensitive)
B-tree catalog partial
Extent overflow
Streaming reads
Resource forks
Unicode names
Generic Read+Seek
Zero dependencies*

* Only byteorder and thiserror — no compression, no FFI, no system libs.

Example: macOS Kernel Debug Kit DMGs contain HFSX (case-sensitive HFS+) partitions. Most Rust HFS libraries can't read case-sensitive volumes — hfsplus handles both.

Features

List directories Browse filesystem tree with names, sizes, timestamps
Read files Extract file contents into memory or stream to a writer
Streaming I/O ForkReader provides Read+Seek access without buffering
File metadata BSD permissions, creation/modification dates, fork info
Recursive walk Walk entire filesystem tree with full paths
Path resolution Navigate by Unix-style paths (/Library/Extensions/foo.kext)

Format Support

Format Support Description
HFS+ Standard Mac OS Extended
HFSX Case-sensitive variant
Legacy HFS Classic Mac OS (pre-1998)
APFS Apple File System (2017+)

Quick Start

Open and Browse

use hfsplus::HfsVolume;
use std::fs::File;
use std::io::BufReader;

let file = File::open("partition.raw")?;
let mut vol = HfsVolume::open(BufReader::new(file))?;

// List root directory
for entry in vol.list_directory("/")? {
    println!("{:?} {:>12} {}", entry.kind, entry.size, entry.name);
}

Read a File

// Read into memory
let data = vol.read_file("/System/Library/Kernels/kernel")?;

// Or stream to a writer (low memory)
let mut out = File::create("kernel")?;
vol.read_file_to("/System/Library/Kernels/kernel", &mut out)?;

Walk Entire Filesystem

for entry in vol.walk()? {
    if entry.entry.kind == hfsplus::EntryKind::File {
        println!("{}: {} bytes", entry.path, entry.entry.size);
    }
}

Streaming File Access

use std::io::Read;

// Open file for random-access Read+Seek without loading into memory
let mut reader = vol.open_file("/large-file.bin")?;
let mut buf = [0u8; 4096];
let n = reader.read(&mut buf)?;

File Metadata

let stat = vol.stat("/Library/Extensions/AppleHDA.kext")?;
println!("Size: {} bytes", stat.size);
println!("Owner: {}", stat.permissions.owner_id);
println!("Mode: {:o}", stat.permissions.mode);
println!("Resource fork: {} bytes", stat.resource_fork_size);

Documentation

Format Specification HFS+ volume header, B-tree, and catalog structures
Implementation Notes Tricky parts: Unicode, extent overflow, node parsing

Example Output

Via dpp-tool hfs (which uses the hfsplus library internally):

$ dpp-tool hfs ls Kernel_Debug_Kit.dmg /

  Kind          Size  Name
  --------------------------------------------------------
  dir              -  .HFS+ Private Directory Data\r
  dir              -  .Trashes
  dir              -  Library
  dir              -  System
  dir              -  usr
              12288  .DS_Store

  1 file(s), 5 directory(ies)
$ dpp-tool hfs info Kernel_Debug_Kit.dmg

  HFS+ Volume: Kernel_Debug_Kit.dmg
  ════════════════════════════════════════════════════════════

  Volume Header
  ────────────────────────────────────────────────────────────
  Signature                HFSX (case-sensitive)
  Version                  5
  Block size               4096 bytes
  Total blocks             260,608
  Free blocks              6
  Files                    3,847
  Folders                  612

Alternatives

Crate HFS+ HFSX B-tree Extents Streaming Generic R Platform
hfsplus All
hfsplus-rs All
hfs-rs partial Unix
hfsfuse N/A Unix (C)

Choose hfsplus if you need:

  • Pure Rust with no FFI or system dependencies
  • HFSX (case-sensitive) volume support
  • Extent overflow file handling for large/fragmented files
  • Generic Read+Seek interface (works with files, memory, network streams)
  • Integration with the dpp pipeline for DMG → HFS+ workflows

Choose hfsfuse if you need:

  • FUSE mounting (kernel-level filesystem access)
  • HFS+ compression support (zlib, lzvn, lzfse)
  • Extended attributes and hard link support

Next Steps

  • Write support — create and modify HFS+ volumes
  • HFS+ compression — decompress transparent compression (zlib, lzvn, lzfse)
  • Extended attributes — read xattr data from the attributes B-tree
  • Hard links — resolve directory and file hard links
  • Journal parsing — read the HFS+ journal for recovery scenarios
  • APFS support — read Apple File System containers (separate crate likely)
  • Allocation bitmap — validate filesystem consistency

License

MIT

Dependencies

~270–720KB
~16K SLoC