Expand description
Filesystem application of parsed chunks (Apply, ApplyContext).
Filesystem application of parsed ZiPatch chunks.
§Parse / apply separation
The crate is intentionally split into two independent layers:
- Parsing (
src/chunk/) — reads the binary wire format and producesChunkvalues. Nothing in the parser allocates file handles, stats paths, or performs I/O against the install tree. - Applying (this module) — takes a stream of
Chunkvalues and writes the patch changes to disk.
The only bridge between the two layers is the Apply trait, which every
chunk type implements. Callers that only need to inspect patch contents can
use the parser without ever touching this module.
§ApplyContext
ApplyContext holds all mutable apply-time state:
- Install root — the absolute path to the game installation directory.
All
SqPackpaths (sqpack/<expansion>/...) are resolved relative to this root by the internal path submodule. - Target platform — selects the
win32/ps3/ps4subfolder suffix used inSqPackfile paths. Defaults toPlatform::Win32and can be overridden either at construction time withApplyContext::with_platformor at apply time when acrate::chunk::sqpk::SqpkTargetInfochunk is encountered. - Ignore flags — control whether missing files and old-data mismatches
produce errors or logged warnings.
SqpkTargetInfochunks set these via the stream; callers can also pre-configure them. - File-handle cache — a bounded map of open file handles. Because a
typical patch applies dozens of chunks to the same
.datfile, re-opening that file for every chunk would be wasteful. The cache avoids this while bounding the number of simultaneously open file descriptors. See the cache section below.
§File-handle cache
Every Apply impl that writes to a SqPack file calls an internal
open_cached method on ApplyContext rather than opening the file
directly. The cache transparently returns an existing writable handle or
opens a new one (with write=true, create=true, truncate=false).
Cached handles are wrapped in a std::io::BufWriter with a 64 KiB
buffer to coalesce the many small writes the SQPK pipeline emits — block
headers, zero-fill runs, decompressed DEFLATE block output — into a
smaller number of write(2) syscalls. Apply functions interact with the
buffered writer transparently because BufWriter implements both Write
and Seek. Call ApplyContext::flush to force buffered data through
to the operating system at a checkpoint of your choosing;
ZiPatchReader::apply_to calls it
automatically before returning.
The cache is capped at 256 entries. When it is full and a new, uncached path is requested, all cached handles are flushed and closed at once before the new one is inserted. This is a simple eviction strategy — it trades some re-open overhead at eviction boundaries for bounded file-descriptor usage. Memory cost at the cap is 256 × 64 KiB = 16 MiB.
Callers should not rely on cached handles persisting across arbitrary
chunks. In particular, crate::chunk::sqpk::SqpkFile’s RemoveAll
operation flushes all cached handles before bulk-deleting files to ensure
no open handles survive into the deletion window (which matters on
Windows). Similarly, DeleteFile evicts the cached handle for the
specific path being removed.
§Ordering and idempotency
Chunks must be applied in stream order. The ZiPatch format is a
sequential log, not a random-access manifest: later chunks may depend on
filesystem state produced by earlier ones (e.g. an AddFile that writes
blocks into a file created by an earlier MakeDirTree or AddDirectory).
Apply operations are not idempotent in general. Seeking to an offset
and writing data is idempotent if the same data is written, but
RemoveAll is destructive and DeleteFile can fail if the file is
already gone (unless ignore_missing is set). Partial application
followed by a retry requires careful state tracking at a higher level;
this crate does not provide transactional semantics.
§Errors
Every Apply::apply call returns crate::Result, which is
Result<(), crate::ZiPatchError>. Errors propagate from:
std::io::Error— filesystem failures (permissions, missing parent directories, disk full, etc.) wrapped ascrate::ZiPatchError::Io.crate::ZiPatchError::NegativeFileOffset— aSqpkFilechunk carried a negativefile_offsetthat cannot be converted to a seek position.
On error, the apply operation aborts at the failing chunk. Any changes already applied to the filesystem are not rolled back.
§Progress and cancellation
Install an ApplyObserver via ApplyContext::with_observer to be
notified after each top-level chunk applies and to signal cancellation
mid-stream. The observer’s
on_chunk_applied method receives a
ChunkEvent with the chunk index, 4-byte tag, and running byte count;
its should_cancel predicate is polled
between blocks inside long-running chunks so that aborting a multi-
hundred-MB SqpkFile AddFile does not have to wait for the whole
chunk to finish. Without an explicit observer, ApplyContext uses
NoopObserver and the existing apply path pays nothing.
§Example
use std::fs::File;
use zipatch_rs::{ApplyContext, ZiPatchReader};
let patch_file = File::open("game.patch").unwrap();
let mut ctx = ApplyContext::new("/opt/ffxiv/game");
ZiPatchReader::new(patch_file)
.unwrap()
.apply_to(&mut ctx)
.unwrap();Re-exports§
pub use checkpoint::Checkpoint;pub use checkpoint::CheckpointPolicy;pub use checkpoint::CheckpointSink;pub use checkpoint::InFlightAddFile;pub use checkpoint::IndexedCheckpoint;pub use checkpoint::NoopCheckpointSink;pub use checkpoint::SequentialCheckpoint;
Modules§
- checkpoint
- Apply-time progress checkpoints — the data the library emits while a patch is being written so a consumer can persist enough state to resume a crashed/interrupted apply later.
Structs§
- Apply
Context - Apply-time state: install root, target platform, flag toggles, and the internal file-handle cache used by SQPK writers.
- Chunk
Event - One chunk-applied event delivered to an
ApplyObserver. - Noop
Observer - No-op observer used by
ApplyContextwhen none is configured.
Enums§
- Apply
Mode - Selects whether
ApplyContextmutates the filesystem or runs in no-op verification mode.
Traits§
- Apply
- Applies a parsed chunk to the filesystem via an
ApplyContext. - Apply
Observer - Hook trait for observing apply-time progress and signalling cancellation.