Documentation
¶
Overview ¶
Apple Data Compression (ADC) decompressor.
ADC is the codec behind UDCO images. It is a byte-oriented LZ77: each control byte introduces either a run of literal bytes or a back-reference into what has already been produced.
Device abstraction for disk images and partitions ¶
DMG reader with decompression support for APFS extraction Based on go-apfs/pkg/disk/dmg implementation by blacktop
Reconstruction helpers for the UDIF/DMG writer: materialise the full raw disk image (or per-block raw data) from an existing DMG so it can be losslessly re-encoded or compared byte-for-byte.
UDIF/DMG writer (encoder): the inverse of dmg_reader.go. Produces a valid UDIF DMG from a set of source blocks, and can losslessly repack an existing DMG by reconstructing its raw image layout and re-encoding it.
On-disk layout produced (all multi-byte fields BIG-ENDIAN):
[data fork: concatenated compressed chunks] [XML plist: resource-fork -> blkx array of mish blocks] [512-byte "koly" trailer]
Every mish block uses DataOffset=0, so each chunk's CompressedOffset is an absolute position within the data fork (which itself starts at file offset 0, DataForkOffset=0). This matches how Apple's hdiutil lays out its images and how dmg_reader.go inverts the offsets.
GPT (GUID Partition Table) parser ¶
Package disk provides utilities for handling disk images (DMG)
Index ¶
- func DecompressADC(src []byte, want int) ([]byte, error)
- func EncodeUDIF(dst io.Writer, blocks []SourceBlock, opts *EncodeOptions) error
- func OpenWithOffset(filename string) (reader io.ReaderAt, offset int64, closer io.Closer, err error)
- func ReconstructRawImage(dmgPath string) ([]byte, error)
- func ReconstructRawImageTo(dst io.WriterAt, dmgPath string) (int64, error)
- func RepackDMG(srcPath, dstPath string, opts *EncodeOptions) error
- func WrapRawImageDMG(dstPath string, raw []byte, partitionHint string, opts *EncodeOptions) error
- func WrapRawImageDMGFrom(dstPath string, src io.ReaderAt, size int64, partitionHint string, ...) error
- type Compression
- type DMGChunk
- type DMGFooter
- type DMGPartition
- type DMGReader
- type Device
- type EncodeOptions
- type GPTHeader
- type GPTPartition
- type SourceBlock
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DecompressADC ¶
DecompressADC decompresses an ADC stream into exactly want bytes.
The caller always knows how long the answer is — a DMG chunk declares it — and passing it in is what makes the decoder safe. Deriving the size from the input instead means guessing a compression ratio, and a guess that is too small turns a valid stream into an out-of-range panic.
func EncodeUDIF ¶
func EncodeUDIF(dst io.Writer, blocks []SourceBlock, opts *EncodeOptions) error
EncodeUDIF writes a complete UDIF DMG for the given source blocks to dst. Blocks are emitted in slice order; each block's chunks are written to the data fork with absolute CompressedOffsets. dst is written strictly in order (data fork, plist, koly trailer) so it need not be seekable.
func OpenWithOffset ¶
func OpenWithOffset(filename string) (reader io.ReaderAt, offset int64, closer io.Closer, err error)
OpenWithOffset opens a disk image and returns an io.ReaderAt for the APFS container plus the byte offset at which the container starts. The image format is detected from content, never from the filename:
- UDIF "koly" trailer in the last 512 bytes -> DMG with on-the-fly decompression (the returned reader is already partition-relative)
- "NXSB" magic at offset 32 -> bare APFS container at offset 0
- "EFI PART" GPT at LBA 1 -> raw image; offset of the Apple_APFS partition
- otherwise -> assume a bare container at offset 0 (the superblock checksum will reject non-APFS data with a clear error)
func ReconstructRawImage ¶
ReconstructRawImage returns the complete raw disk image encoded by the DMG at dmgPath: every block (zero-fill and ignored materialised as zeros, others decompressed) placed at its absolute sector offset. The result is a byte-exact reproduction of the original raw image.
The entire image is held in memory, so it is only suitable for images that comfortably fit. Prefer ReconstructRawImageTo, which streams, or RepackDMG, which never assembles the image at all.
func ReconstructRawImageTo ¶
ReconstructRawImageTo writes the complete raw disk image encoded by the DMG at dmgPath to dst, placing every block at its absolute sector offset. Zero-fill and ignored chunks become zeros, everything else is decompressed. The result is a byte-exact reproduction of the original raw image.
Nothing larger than one chunk is held in memory, so this works on an image of any size. It returns the raw image length in bytes.
func RepackDMG ¶
func RepackDMG(srcPath, dstPath string, opts *EncodeOptions) error
RepackDMG reconstructs the raw image layout of the source DMG at srcPath and re-encodes it losslessly to dstPath, preserving every block boundary and name so both this package's reader and hdiutil handle the output exactly as they handle the input. The chunk data is recompressed per opts.
func WrapRawImageDMG ¶
func WrapRawImageDMG(dstPath string, raw []byte, partitionHint string, opts *EncodeOptions) error
WrapRawImageDMG writes a UDIF DMG at dstPath wrapping a raw file system image as a single Apple partition block. partitionHint is the Apple partition type name embedded in the block name so the reader (and hdiutil) locate the file system, e.g. "Apple_HFSX", "Apple_HFS" or "Apple_APFS".
The whole image is held in memory. WrapRawImageDMGFrom takes the same image as an io.ReaderAt and does not.
func WrapRawImageDMGFrom ¶
func WrapRawImageDMGFrom(dstPath string, src io.ReaderAt, size int64, partitionHint string, opts *EncodeOptions) error
WrapRawImageDMGFrom writes a UDIF DMG at dstPath wrapping the raw file system image read from src, which must cover [0, size). It is WrapRawImageDMG without holding the image in memory: nothing larger than one chunk is retained, so src may be an *os.File of any size.
The output is byte-identical to what WrapRawImageDMG produces for the same bytes; only where they come from differs.
Types ¶
type Compression ¶
type Compression int
Compression selects the chunk compressor used by the encoder.
const ( // CompressionZlib compresses each non-zero chunk with zlib (UDZO chunk // type), falling back to raw storage when compression does not shrink the // chunk. It is the library default and is understood by both this package's // reader and hdiutil. CompressionZlib Compression = iota // CompressionNone stores every non-zero chunk raw (uncompressed). CompressionNone // CompressionLZFSE compresses each non-zero chunk with LZFSE (ULFO chunk // type), Apple's modern DMG codec. It gives a better ratio than zlib at // higher speed and is what hdiutil produces by default on recent macOS. // Like the others it falls back to raw storage for a chunk it cannot shrink. CompressionLZFSE // CompressionLZMA compresses each non-zero chunk with LZMA (ULMO chunk // type), the raw LZMA1 "alone" stream both this package's reader and hdiutil // accept. It gives the best ratio of the set at the cost of speed. CompressionLZMA )
type DMGChunk ¶
type DMGChunk struct {
Type uint32
Comment uint32
DiskOffset uint64 // Logical offset in bytes
DiskLength uint64 // Length in bytes
CompressedOffset uint64 // Offset in DMG file
CompressedLength uint64 // Compressed size in bytes
}
DMGChunk represents a compressed chunk in a DMG partition
type DMGPartition ¶
type DMGPartition struct {
Name string
StartSector uint64
SectorCount uint64
DataOffset uint64
Chunks []DMGChunk
}
DMGPartition represents a partition within a DMG
type DMGReader ¶
type DMGReader struct {
// contains filtered or unexported fields
}
DMGReader implements io.ReaderAt for reading from compressed DMG files
type Device ¶
Device is a random-access, sized, closable view of a disk image or a partition within one. Implementations must return partition-relative data from ReadAt when they represent a partition (as DMGReader does for the APFS partition inside a DMG).
type EncodeOptions ¶
type EncodeOptions struct {
// Compression is the chunk compressor (default CompressionZlib).
Compression Compression
// ChunkSectors is the number of 512-byte sectors per chunk
// (default encodeDefaultChunkSectors). Larger chunks compress slightly
// better; smaller chunks give finer random-access granularity.
ChunkSectors uint64
// NoChecksums disables CRC32 checksum emission (all checksum fields are
// written as UDIF "none", type 0). By default CRC32 (type 2) checksums
// are emitted for each block, the data fork, and the master checksum.
NoChecksums bool
// ZlibLevel is the zlib compression level (zlib.DefaultCompression when 0
// is passed via the option struct is treated as default). Accepts the
// standard compress/zlib levels.
ZlibLevel int
}
EncodeOptions controls how EncodeUDIF/RepackDMG produce a DMG.
type GPTHeader ¶
type GPTHeader struct {
Signature gptMagic
Revision uint32
HeaderSize uint32
CRC32 uint32
Reserved uint32
HeaderStartLBA uint64
BackupLBA uint64
FirstUsableLBA uint64
LastUsableLBA uint64
DiskGUID gptGUID
EntriesStart uint64
EntriesCount uint32
EntriesSize uint32
PartitionsCRC32 uint32
Padding [420]byte
}
GPTHeader is a GPT header structure
type GPTPartition ¶
type GPTPartition struct {
Type gptGUID
ID gptGUID
StartingLBA uint64
EndingLBA uint64
Attributes uint64
PartitionNameUTF16 [72]uint8
}
GPTPartition is a GPT partition entry
func (GPTPartition) IsEmpty ¶
func (p GPTPartition) IsEmpty() bool
IsEmpty returns if the partition is empty
type SourceBlock ¶
type SourceBlock struct {
Name string
CFName string
ID string
Attributes string
StartSector uint64
// SectorCount is the number of 512-byte sectors the block covers. When
// Data is non-nil it must equal len(Data)/512; otherwise it is authoritative.
SectorCount uint64
// Data is the exact uncompressed bytes for the block, length a multiple of
// 512. A nil Data and a nil Reader mean an all-zero block of SectorCount
// sectors.
Data []byte
// Reader supplies the block's uncompressed bytes lazily, covering
// [0, SectorCount*512) in block-relative coordinates. It is the alternative
// to Data for a block too large to hold in memory; setting both is an error.
//
// The encoder reads it in ascending, chunk-sized windows and never retains
// more than one chunk, so a block of any size costs a fixed amount of memory.
Reader io.ReaderAt
}
SourceBlock is one blkx block to encode. Its raw bytes cover the half-open sector range [StartSector, StartSector+SectorCount).