-
Notifications
You must be signed in to change notification settings - Fork 0
Virtual File System
This page explains how SimpleXisoDrive turns an XDVDFS directory tree into a Windows-visible, read-only volume. It covers path resolution, caching, every Dokan operation, and the read-only guarantees.
VfsContainer is the bridge between the Dokan operations layer and the raw ISO stream. It is created
once per mount and disposed on unmount.
- A new
IsoStopens the ISO file withFileMode.Open,FileAccess.Read, andFileShare.ReadWrite(shared access lets antivirus and indexing tools open the file too). -
VolumeDescriptor.ReadFromprobes the five known descriptor locations and setsIsoSt.VolumeOffsetto the winning partition offset. - If validation fails,
InvalidImageExceptionis thrown:- the original
InvalidImageExceptionis rethrown unchanged when the descriptor was readable but invalid; - any other failure is wrapped with
Failed to read Xbox ISO: <message>.
- the original
- The volume size is taken from the stream length, the creation time from the descriptor, and the
synthetic root
FileEntry(\) is cached.
| Member | Behavior |
|---|---|
VolumeSize |
Length of the ISO in bytes. |
VolumeCreationTime |
Timestamp from the volume descriptor; DateTime.MinValue when invalid. |
GetEntry(path) |
Resolves a virtual path to a FileEntry, or null. Never throws. |
GetFolderList(path) |
Lazily enumerates the children of a directory. Returns nothing when the path is not a valid directory. |
ReadFile(entry, buffer, offset) |
Reads file data; returns the number of bytes read, or 0 on failure. |
Dispose() |
Closes the underlying stream. |
Virtual paths use backslashes. Normalization:
| Input | Normalized |
|---|---|
/Games/Halo |
\Games\Halo |
\Games\Halo\ |
\Games\Halo |
"" |
\ |
\ |
\ |
Entry lookup is case-insensitive. The root path always resolves to the synthetic root entry created during construction.
GetEntry resolves a path as follows:
- If the path is
\, return the cached root entry. - If the path is already in the entry cache, return it.
- Split the path into parent directory and file name.
- Resolve the parent recursively; it must be a directory.
- Search the parent's directory table for the name (case-insensitive).
- Cache and return the result.
Every step is wrapped so that a failure logs an error and returns null instead of propagating to
Dokan.
Windows can send special relative segments. XboxIsoVfsDokan.NormalizePath handles them:
| Input path | Normalized |
|---|---|
\ |
\ |
\. or \..
|
\ |
\Games\. |
\Games |
\Games\Halo\.. |
\Games |
/ separators |
Converted to \
|
GetFolderList enumerates the entries of a directory table:
- If the listing is cached, it is replayed from the cache.
- Otherwise the directory entry is resolved and its first child is read from offset
0of its start sector. - The binary tree is traversed iteratively with an explicit stack (left children processed first).
- Entries with empty names are skipped; every named entry is cached by full path and yielded.
- The complete list is stored in the children cache.
Traversal safety:
- visited nodes are tracked by
(EntrySector, EntryOffset), preventing cycles; - each traversal is limited to 100,000 nodes and aborts with an error log when exceeded;
- self-referencing child pointers are rejected.
XboxIsoVfsDokan.FindFiles augments directory listings with Windows-style virtual entries:
| Entry | When added |
|---|---|
. |
Always |
.. |
Every directory except the root |
Both virtual entries are reported as read-only directories and carry the volume creation time.
The table lists every operation implemented by XboxIsoVfsDokan, its behavior, and the status codes
it can return.
| Operation | Behavior | Status codes |
|---|---|---|
CreateFile |
Opens a handle; resolves the path and stores the FileEntry in info.Context. Denies write access, creation, and truncation. Directory/file type mismatches are reported precisely. |
Success, FileNotFound, AccessDenied, AlreadyExists, PathNotFound, NotADirectory, Error
|
ReadFile |
Reads up to the buffer size, clamped to the remaining file size. Returns InvalidHandle for directories. A read at or beyond the file size returns Success with 0 bytes. |
Success, InvalidHandle, Error
|
GetFileInformation |
Returns name, attributes, size, and timestamps. Directories report length 0. An empty name is reported as Unknown. |
Success, FileNotFound, Error
|
FindFiles |
Lists ., .., and all real children. Requires a directory. |
Success, NotADirectory, Error
|
FindFilesWithPattern |
Lists children matching a wildcard translated to a case-insensitive regex with a 1-second match timeout. . and .. are always included. |
Success, NotADirectory, Error
|
GetFileSecurity |
Builds a FileSecurity or DirectorySecurity granting Everyone read and execute access. |
Success, Error
|
GetVolumeInformation |
Returns the volume label XBOX_ISO, file system XDVDFS, maximum component length 255, and features `ReadOnlyVolume |
CasePreservedNames |
GetDiskFreeSpace |
Reports the ISO size as total capacity and 0 free bytes. |
Success, Error
|
FindStreams |
Alternate data streams are not supported. | NotImplemented |
LockFile / UnlockFile
|
No-op, reported as successful. | Success |
| Operation | Behavior |
|---|---|
Cleanup, CloseFile
|
Empty: no per-handle resources exist. |
Mounted, Unmounted
|
Return Success; exceptions are logged. |
| Operation | Status |
|---|---|
WriteFile |
AccessDenied (bytes written = 0) |
FlushFileBuffers |
AccessDenied |
SetFileAttributes |
AccessDenied |
SetFileTime |
AccessDenied |
DeleteFile |
AccessDenied |
DeleteDirectory |
AccessDenied |
MoveFile |
AccessDenied |
SetEndOfFile |
AccessDenied |
SetAllocationSize |
AccessDenied |
SetFileSecurity |
AccessDenied |
The read-only volume option is already requested from Dokan, so most write attempts are rejected by the driver; the explicit denials are a second line of defense.
| Property | Value |
|---|---|
| Creation time | Volume creation time |
| Last access time | Volume creation time |
| Last write time | Volume creation time |
| Directory length | 0 |
| File length |
FileSize from the directory entry |
| Attributes | Always include ReadOnly; mapped from XDVDFS flags |
| Security |
Everyone: ReadAndExecute allowed |
Windows may cache metadata, so all files appear to have the disc's creation timestamp.
All public operations except the empty lifecycle methods run through
ExecuteWithReporting(operation, fileName, action):
- Execute the action.
- On success, return its
NtStatus. - On exception, log
Dokan operation {Operation} failed for '{FileName}'at Error level, then returnDokanResult.Error.
Because the Serilog pipeline includes BugReportSink at Warning level, such failures are also
written to error.log and can be forwarded to the bug report API. See
Services and Privacy and Networking.
-
IsoStserializes every stream seek/read pair on a single lock, so concurrent reads cannot corrupt the stream position. - The
VfsContainercaches are populated on demand while servicing requests and are not explicitly synchronized; they are designed for the common case where the first directory listing populates them for later lookups. -
GetFolderListis an iterator; enumeration happens on the calling Dokan thread while the underlying stream lock is taken per read.
User guide
Technical reference
Development