pydmg
pydmg is a cross-platform Python library for reading, inspecting, extracting, and creating Apple DMG files.
It uses the Rust crate apple-dmg under the hood and exposes a Pythonic API.
- License: MIT
- Core Rust dependency:
apple-dmg(Apache-2.0 OR MIT, MIT-compatible) - DMG/HFS+/APFS backends:
udif,hfsplus, andapfs(MIT) - Third-party notices:
THIRD_PARTY_NOTICES.md - Build backend:
maturin+pyo3 - Platforms: macOS, Linux, Windows
- Distribution: prebuilt wheels for major architectures + source distribution (
sdist) for any architecture with Rust toolchain
Features
- Read DMG trailer (
koly) metadata and checksum fields. - Parse plist metadata and return a JSON-serializable structure.
- Extract metadata candidates for:
- creation and modification dates/timestamps
- author/creator-like fields
- creation application/tool fields
- List partitions and their BLKX chunk tables.
- Inspect GPT partition-table metadata when GPT is present in DMG partitions.
- Inspect filesystem metadata for FAT12/16/32 partitions.
- Auto-detect and inspect HFS+/APFS metadata through a bounded
udifextraction adapter. - Decompress raw, zero-fill, zlib, bzip2, and LZFSE partition chunks with checked limits.
- Verify data fork CRC32 checksum.
- List and extract files from FAT32 DMG partitions.
- List and extract files from auto-detected HFS+/APFS DMG filesystems.
- Create new DMGs from a source directory.
Installation
From PyPI
pip install pydmg
From source (local development)
Requirements:
- Python 3.9+
- Rust 1.98.1 for reproducible repository builds (the crate's tested MSRV remains 1.88)
- C/C++ compiler toolchain
Platform notes for source builds:
- Linux: install
build-essential,pkg-config,libbz2-dev,liblzma-dev - macOS: install Xcode Command Line Tools and
pkg-config - Windows: install Visual Studio Build Tools (MSVC C++)
pip install -e ".[dev]"
Quick Start
from pathlib import Path
import pydmg
info = pydmg.inspect("example.dmg")
print(info["koly"]["version"])
print(info["checksum"]["data_fork_checksum_matches"])
parts = pydmg.list_partitions("example.dmg")
print([p["name"] for p in parts])
gpt_info = pydmg.inspect_gpt("example.dmg")
print(gpt_info["has_gpt"])
fat_entries = pydmg.list_fat32_entries("example.dmg", partition_index=1)
print(fat_entries[:5])
pydmg.extract_fat32("example.dmg", "./out", partition_index=1)
fs_info = pydmg.inspect_filesystems("example.dmg")
print(fs_info["fat_filesystems"])
# For HFS+/APFS DMGs:
# entries = pydmg.list_apple_entries("macos_installer.dmg", "/")
# pydmg.extract_apple_file("macos_installer.dmg", "/path/in/image.pkg", "./image.pkg")
pydmg.create_dmg(
source_dir=Path("./payload"),
output_path=Path("./payload.dmg"),
volume_label="PAYLOAD",
total_sectors=32768,
)
API Surface
Top-level functions
inspect(path)inspect_filesystems(path)list_partitions(path)inspect_gpt(path, partition_index=None, strict=False)read_partition(path, index)extract_partition(path, index, output_path)compute_data_checksum(path)verify_data_checksum(path)list_fat32_entries(path, partition_index=1)extract_fat32(path, output_dir, partition_index=1, overwrite=False)list_apple_entries(path, directory_path="/")read_apple_file(path, file_path)extract_apple_file(path, file_path, output_path)create_dmg(source_dir, output_path, volume_label="PYDMG", total_sectors=32768)
Object API
DmgImage(path) provides convenience wrappers over the same operations.
Function Reference
All paths accept str or pathlib.Path.
Common error behavior:
- Raises
RuntimeErrorwhen parsing, decompression, or filesystem reads fail. - Raises
IndexErrorwhen a requested partition index is outside the parsed partition list. - Raises
ValueErrorfor invalid user input (for example invalidcreate_dmgarguments). - Catches HFS+/APFS dependency panics and returns
RuntimeError; Rust's panic hook may still emit a diagnostic to stderr for a malformed image.
DMG inspection and metadata
inspect(path) -> dict
- Returns DMG-level details including:
kolytrailer valueschecksumfields and CRC comparison result- parsed
plist metadata_candidates(date/author/tool-like fields)- partition metadata and chunk tables
inspect_filesystems(path) -> dict
- Returns detected filesystem metadata including:
fat_filesystemslist (FAT12/16/32 metadata)apple_filesystem(HFS+/APFS metadata when detected)errorslist for non-fatal detection failures
inspect_gpt(path, partition_index=None, strict=False) -> dict
- Scans one partition or all partitions for GPT metadata.
- If no GPT is found and
strict=False, returnshas_gpt: false. - If no GPT is found and
strict=True, raisesRuntimeError.
list_partitions(path) -> list[dict]
- Returns parsed DMG partition records with BLKX chunk info.
Example:
import pydmg
info = pydmg.inspect("image.dmg")
print(info["metadata_candidates"])
fs = pydmg.inspect_filesystems("image.dmg")
print(fs["fat_filesystems"])
print(fs["apple_filesystem"])
gpt = pydmg.inspect_gpt("image.dmg", strict=False)
print(gpt["has_gpt"])
parts = pydmg.list_partitions("image.dmg")
print(len(parts))
Partition payload and checksums
read_partition(path, index) -> bytes
- Reads and decompresses the partition payload at
index. - Rejects partitions that expand beyond 512 MiB, compressed chunks larger than 256 MiB, expanded chunks larger than 64 MiB, and non-contiguous BLKX output layouts.
- ADC-compressed chunks are unsupported by the upstream DMG decoders and raise
RuntimeError.
extract_partition(path, index, output_path) -> int
- Atomically replaces
output_pathonly after the complete payload is written and synchronized. - Replaces a final symlink itself rather than following it to its target.
compute_data_checksum(path) -> int
- Computes DMG data-fork CRC32.
verify_data_checksum(path) -> bool
- Compares computed CRC32 to the trailer-declared checksum.
Example:
payload = pydmg.read_partition("image.dmg", 0)
print(len(payload))
written = pydmg.extract_partition("image.dmg", 0, "part0.bin")
print(written)
print(pydmg.compute_data_checksum("image.dmg"))
print(pydmg.verify_data_checksum("image.dmg"))
FAT32 filesystem helpers
list_fat32_entries(path, partition_index=1) -> list[dict]
- Lists FAT entries with path/type/size metadata.
extract_fat32(path, output_dir, partition_index=1, overwrite=False) -> list[str]
- Extracts files from the selected FAT partition.
- Returns extracted relative paths.
- Rejects a symlink output root, symlink path components, and symlink file destinations.
- Stops after 100,000 entries, nesting deeper than 128, 512 MiB aggregate file data, 576 MiB of dependency reads, or 2,000,000 dependency read operations.
- This bulk API writes image-derived names. The assessed deployment profile instead writes bytes only to caller-selected files; use this separate API only with a caller-controlled output tree.
Example:
entries = pydmg.list_fat32_entries("image.dmg", partition_index=1)
print(entries[:3])
files = pydmg.extract_fat32("image.dmg", "out/fat", partition_index=1, overwrite=True)
print(files[:3])
HFS+ and APFS filesystem helpers
list_apple_entries(path, directory_path="/") -> list[dict]
- Auto-detects HFS+ or APFS and lists directory entries.
- Preflights HFS+ allocation blocks and APFS block/checkpoint metadata before entering the third-party filesystem parsers.
read_apple_file(path, file_path) -> bytes
- Reads a single file from detected HFS+/APFS filesystem.
- Rejects output beyond 512 MiB.
extract_apple_file(path, file_path, output_path) -> int
- Atomically replaces
output_pathafter a complete bounded write and returns bytes written. - Failure preserves an existing destination.
Example:
entries = pydmg.list_apple_entries("mac_image.dmg", "/")
print(entries[:5])
data = pydmg.read_apple_file("mac_image.dmg", "/README.txt")
print(len(data))
written = pydmg.extract_apple_file("mac_image.dmg", "/README.txt", "out/README.txt")
print(written)
DMG creation
create_dmg(source_dir, output_path, volume_label="PYDMG", total_sectors=32768) -> None
- Creates a DMG from a directory.
total_sectorsuses 512-byte sectors.- The maximum created image is 1,048,576 sectors (512 MiB).
- Creation uses a sibling temporary file and atomically replaces the final output on success.
- The assessed threat model assumes the caller-controlled source tree remains immutable while the image is created.
Example:
from pathlib import Path
import pydmg
pydmg.create_dmg(
source_dir=Path("payload"),
output_path=Path("payload.dmg"),
volume_label="PAYLOAD",
total_sectors=32768,
)
DmgImage convenience object
DmgImage(path) wraps the same top-level APIs as instance methods.
Example:
img = pydmg.DmgImage("image.dmg")
print(img.inspect()["koly"]["version"])
print(img.inspect_filesystems()["apple_filesystem"])
print(img.checksum_valid())
Testing
pytest
The test suite covers:
- DMG creation from a fixture directory
- inspection payload completeness
- checksum computation/verification
- GPT inspection behavior (non-GPT reporting and strict mode)
- partition read/extract
- FAT32 listing and extraction
- filesystem metadata inspection (FAT + HFS+/APFS auto-detect behavior)
- HFS+ positive listing/read/extract using upstream
hfsplus-rsfixture image - APFS positive listing/read/extract using non-malware
linearmousefixture image - partition index error behavior
- BLKX count/truncation and checked range rejection
- zlib, bzip2, and LZFSE decoding plus decompression ceilings
- positive in-memory GPT parsing, GPT assertion/CRC preflight, and pre-allocation plist limits
- FAT and direct-output symlink defenses and atomic failure behavior
- FAT/HFS+/APFS dependency read budgets and panic containment
The current suite contains 22 Python tests and 18 cross-platform native Rust tests, plus one Unix path-panic regression. CI enforces 90% Python line coverage and 70% native Rust line coverage as separate measurements.
Performance
FAT filesystems are served through a bounded seekable BLKX reader, so directory listing and file extraction decompress only requested chunks instead of materializing an entire partition. Direct partition reads and atomic extraction stream into their final sink, with reusable LZFSE buffers and no per-chunk staging copy.
The release-mode benchmark method, raw samples, profiles, artifact-size tradeoffs, and dated
before/after results are in PERFORMANCE.md. CI records five-sample evidence for
each immutable revision, and the tag-gated release workflow records nine samples before building
distribution artifacts.
Security, audit, and fuzzing
DMGs and embedded filesystem structures are untrusted binary input. Review the
SECURITY.md threat model and safe-use guidance before processing images from an
untrusted source. The dated coverage, dependency, CI, documentation, and security findings are in
AUDIT.md; reproducible coverage-guided fuzzing instructions are in
FUZZING.md.
Repository-owned range, decompression, plist pre-allocation, GPT, FAT-read, checksum,
output-atomicity, lint, test, and CI findings have local remediations. APFS parser panics and
APFS/HFS traversal-budget defects are bounded or contained where possible but remain open
upstream; ADC decoding remains an explicit fail-closed compatibility limitation. The obsolete XAR
dependency path was removed, so the locked graph uses patched quick-xml 0.41.0 with no advisory
exceptions. The active threat model is a static attacker-crafted image, immutable during
processing, with caller-selected output files and no hostile concurrent filesystem writer. CPU and
memory exhaustion are deferred in the current assessment. Provenance is not required, and selected
content is recorded only as inert bytes or text with no active execution. Sandbox and host limits
remain broader defense in depth. A successful CRC32 check is not authenticity verification.
API Docs (pydoc)
Generate HTML API docs locally:
python scripts/build_pydoc.py
This writes pydmg.html in the current directory. CI also verifies that pydoc
build succeeds.
GitHub Actions and PyPI
This repo includes workflows for:
- CI: Python 3.9–3.13 and Rust tests, lint, strict typing, Bandit, dependency audits, MSRV, and separate Python/native coverage and release-performance evidence gates
- Fuzz: required PR smoke and scheduled AddressSanitizer campaigns; sensitive failures remain on the runner for private reproduction rather than being uploaded from the public repository
- Release: repeat quality/security/coverage/fuzz gates, build wheels and source distribution, then publish to PyPI through trusted publishing
Release workflow targets:
- Linux:
x86_64,aarch64 - macOS:
x86_64,arm64 - Windows:
x86_64 - Plus
sdistfor architecture-independent source release
For publishing, configure PyPI trusted publishing for this repository and push a tag like v0.1.2.
Detailed release steps are documented in RELEASE.md.
Licensing Notes
- Project license: MIT (
LICENSE) - Third-party attribution and fixture provenance:
THIRD_PARTY_NOTICES.md - Test fixture source details:
tests/fixtures/README.md - No Paragon APFS SDK code is included
Notes on metadata completeness
DMG metadata fields vary by producer and format. pydmg returns:
- parsed plist payload (JSON-compatible representation)
- extracted metadata candidates based on key patterns
This gives broad coverage of creation dates, creators/authors, and creation applications when present.
Metadata
Release files for pydmg 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pydmg-0.1.2.tar.gz | 3.1 MB | With provenance | Details for pydmg-0.1.2.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| pydmg-0.1.2-cp39-abi3-win_amd64.whl | CPython 3.9 | abi3 | Windows x86-64 | Details for pydmg-0.1.2-cp39-abi3-win_amd64.whl |
| pydmg-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ x86-64 | Details for pydmg-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
| pydmg-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ ARM64 | Details for pydmg-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
| pydmg-0.1.2-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details for pydmg-0.1.2-cp39-abi3-macosx_11_0_arm64.whl |
| pydmg-0.1.2-cp39-abi3-macosx_10_12_x86_64.whl | CPython 3.9 | abi3 | macOS 10.12+ x86-64 | Details for pydmg-0.1.2-cp39-abi3-macosx_10_12_x86_64.whl |
Total release size: 7.4 MB
Release files / pydmg-0.1.2.tar.gz
| Download URL | pydmg-0.1.2.tar.gz |
|---|---|
| Size | 3.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
94f9e264089b28eca8b20cfa13426f4d78302fa2bba5473d6b92757e3cc5d0ee
|
|
BLAKE2b-256 checksum How to use checksums |
b0fcb51ac7aaef5bc8dd5bd49b4b953e9e18b26cad6496f42836cfcb125de490
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / pydmg-0.1.2-cp39-abi3-win_amd64.whl
| Download URL | pydmg-0.1.2-cp39-abi3-win_amd64.whl |
|---|---|
| Size | 722.9 kB |
| Tags | CPython 3.9 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
7e0e128bf612176db8326a3ebcbaf9be7e9a56967177905abc675e325cbdf9f2
|
|
BLAKE2b-256 checksum How to use checksums |
5c9d60858c52705e2999e6d97ffe5b973f43b32ee60e52b29c1dd513f9691ccd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / pydmg-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | pydmg-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 930.4 kB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
f73a6436d37778948e023cdd9815ad82054717e1fe43e46a00a7ec7851d1e972
|
|
BLAKE2b-256 checksum How to use checksums |
234876fbd3414550c70908498029622bf7d2e2e7bde3d5fc027ef595f74c9e94
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / pydmg-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | pydmg-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 934.7 kB |
| Tags | CPython 3.9 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
981b3349387494ed58f84222a5b087ed5e7586141d6421b9d410ca40e4101d81
|
|
BLAKE2b-256 checksum How to use checksums |
e4eef8bd6032a3a44d495ec798f2de2a9188eb61988cf1f6a8c3d5f118760f37
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / pydmg-0.1.2-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | pydmg-0.1.2-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 830.7 kB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
051ac54029cce19bdd352e608d5040104824875963f64f0cd0e880e17d2db7fe
|
|
BLAKE2b-256 checksum How to use checksums |
e268158276b24d71bffeb6ef53ab73aac154ccc0c37dc3854e3fe15f23d5456b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / pydmg-0.1.2-cp39-abi3-macosx_10_12_x86_64.whl
| Download URL | pydmg-0.1.2-cp39-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 821.9 kB |
| Tags | CPython 3.9 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
6eed028357f379ff137eebbaaf573c4ef9d106ccdeca81147f1fb979a013f0b1
|
|
BLAKE2b-256 checksum How to use checksums |
293494277e54e9b5770d5b17d356d773e479f8acb4744e47b8ede5a5717af76f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logSecurity for pydmg 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 6 files in this release have been uploaded with provenance metadata.
Attestation for pydmg-0.1.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.