# Architecture ## Overview VirtualFS is a virtual filesystem layer for .NET applications. It combines multiple storage backends into one unified virtual tree. At a high level: - every backend implements `IFileSystem` - a `RootFileSystem` mounts many backends under virtual paths - callers operate on virtual paths like `/assets/logo.png` - the root dispatches operations to the mounted backend that owns the target path This gives the library an overlay-style design similar to a mount table. ## Core Types ### `Path` VirtualFS uses its own `VirtualFS.Path` type instead of platform-native path handling. Rules: - all paths are rooted - `/` is the root - a trailing `/` means directory - no trailing `/` means file - separator is always `/` - `.` is ignored - `..` is normalized but cannot escape root Examples: ```csharp using VirtualFS; Path root = new Path(); // "/" Path dir = "/content/"; // directory Path file = "/content/app.js"; // file Path combined = dir + "app.js"; // "/content/app.js" ``` Important: - `/content` and `/content/` are different paths ### `Entry`, `Directory`, `File` The public object model is based on three types: - `Entry` - `Directory` - `File` `Entry` contains: - path - owning filesystem - read-only state - timestamps `Directory` adds: - enumeration helpers - child lookup - directory creation - file creation - delete operations `File` adds: - open for read/write - convenience read helpers - convenience write helpers - delete operations ### Local Path vs Full Path For entries returned from mounted filesystems: - `Path` is local to the owning backend - `FullPath` is the path as seen from the root This distinction matters when the same backend is mounted under a non-root path. ## Filesystem Model ### `IFileSystem` Represents a backend filesystem. Main responsibilities: - existence checks - metadata lookup - enumeration - create, delete, move, copy, rename - file stream access - optional mapping back to a physical path or URI-like location ### `IRootFileSystem` Extends `IFileSystem` with mount management: - `Mount` - `Umount` - `GetMounted` - `GetMountPath` - `Root` ### `BaseFileSystem` `BaseFileSystem` provides shared behavior for backend implementations. Important responsibilities: - tracks read-only state - tracks mount priority - tracks open stream count through `VirtualStream` - provides generic copy/move behavior when a backend does not override it ## Root Composition `RootFileSystem` is the composition layer. It is itself read-only, but mounted filesystems may be writable. Typical setup: ```csharp using System.IO; using VirtualFS.Compressed; using VirtualFS.Implementation; using VirtualFS.Memory; using VirtualFS.Physical; var root = new RootFileSystem(); root.Mount(new PhysicalFileSystem(new DirectoryInfo("/srv/site")), "/"); root.Mount(new ZipReadFileSystem(zipStream), "/assets/"); root.Mount(new MemoryFileSystem(), "/generated/"); ``` After mounting: - `/index.html` can resolve from the physical filesystem - `/assets/...` can resolve from the ZIP - `/generated/...` can resolve from memory ## Mount Priority When multiple filesystems are mounted under the same virtual directory, resolution order is controlled by `FileSystemMountPriority`. Values: - `High` - `Normal` - `Low` Current behavior: - `High` mounts are checked first - `Low` mounts are checked last - `Normal` mounts are placed between them This supports overlay patterns such as: - immutable base content from a ZIP - writable overrides from disk - generated files from memory ## Local vs Rooted Operations Many `Directory` and `File` instance methods accept `forceLocal`. Behavior: - `forceLocal: false` uses the owning root filesystem if one exists - `forceLocal: true` keeps the operation inside the mounted backend This matters when several filesystems overlap. ## Copy and Move Behavior The library can copy and move across filesystem boundaries. Behavior to understand: - same-backend operations may use optimized backend-specific implementations - cross-backend operations may fall back to stream-based copy logic - moves across backends may become copy-then-delete - deep remote copies can be slower than native host operations ## Streams and Busy State Open streams are wrapped in `VirtualStream`. Purpose: - increment and decrement backend open counts - keep backend-specific transport state alive while a stream is open - support `IsBusy` Practical implication: - a busy filesystem cannot be unmounted - callers should dispose streams promptly