FileDiskIo
A DiskIo backed by real files under basePath, via the platform RandomAccessStorage. Ports the piece↔file mapping logic of libtorrent's default_storage/mmap_storage (storage_utils.cpp): the torrent is a single concatenated byte stream, and a piece read/write fans out across whichever files its byte range overlaps.
Blocking file syscalls run on dispatcher (defaults to Dispatchers.Default; callers on JVM/Android should inject Dispatchers.IO, which is not available in commonMain).
Concurrency: a shared RandomAccessStorage does an internal seek then read/ write, so two concurrent peers hitting the same file handle would interleave a seek from one with the read from the other and corrupt data. Every handle is therefore guarded by its own Mutex making each seek+transfer atomic, and the handle map itself is guarded so lazy-open is race-free.
Part-file: blocks that belong to excluded (priority-0) files or BEP-47 padding files are not written to the real files. They are routed into a side <name>.parts file (libtorrent's part_file, part_file.cpp), keyed by piece index, so the data is still readable for hashing/verification and is reclaimed when the file's priority later rises. This mirrors libtorrent's behavior of never touching the destination file of a priority-0 file.
Allocation: storageMode chooses sparse files (the default) or full preallocation (ALLOCATE), matching libtorrent's storage_mode_t.
Resume note: checkExistingFiles always reports nothing as present, so every start looks like a fresh download. Verified resume hashes the on-disk pieces against the torrent hashes, and it runs in the engine's recheck path, where the expected hashes live.
Constructors
Functions
Which pieces do we already have on disk? Drives the initial resume/recheck.
Hash a fully-downloaded piece for verification against the torrent's hashes.
Move all storage to newSavePath, the counterpart of libtorrent's async_move_storage (storage_utils.cpp move_storage). Open handles are flushed and closed, the on-disk files (and any part-file) are relocated under the new save path, and subsequent reads/writes target the new location. A best-effort, no-op default is provided for backends without on-disk state (e.g. the in-memory double).