<p align="center">
<img src="logo.png" alt="ALPack" width="300"/>
</p>
<h1 align="center">OverlayFS Fuse - A FUSE-based overlay filesystem in Rust</h1>
Stacks a read-only **lower** layer under a read-write **upper** layer, exposing
a unified mount point with full Copy-on-Write (CoW) semantics, whiteout-based
deletion, and flexible commit strategies.
## โจ Features
- ๐ **Copy-on-Write**
Writes are promoted to the upper layer; the lower layer is never modified.
- ๐๏ธ **Whiteout support**
Deletions and renames create `.wh.<name>` markers to hide lower-layer entries.
- ๐ **Four finalization strategies**
`Preserve`, `Discard`, `Commit`, and `CommitAtomic` (crash-safe backup/swap merge).
- ๐ **Symlink-aware**
Dangling symlinks in the lower layer are tolerated; CoW never follows symlinks when copying.
- ๐งฌ **Extended attribute preservation**
`xattrs`, permissions, ownership, and timestamps are carried through CoW and commits.
- ๐งฎ **Dual inode modes**
`Virtual` (sequential, ephemeral) or `Persistent` (FNV-1a hash, stable across remounts).
- ๐ **Thread-safe inode store**
Single-`Mutex` design eliminates TOCTOU races in concurrent lookup/allocation.
- ๐งพ **Content-based deduplication on commit**
Files are compared by size, mtime, and BLAKE3 hash before overwriting.
## ๐ Quick Start
```rust
use overlay_fuse::{OverlayFS, OverlayAction};
use std::path::PathBuf;
// 1. Create an overlay over an existing directory.
let mut overlay = OverlayFS::new(PathBuf::from("/path/to/lower"));
// 2. Mount โ changes go to <lower>.upper, visible at <lower>.mountpoint
overlay.mount().expect("mount failed");
// 3. Use the mount point like any normal directory.
let mp = overlay.handle().mount_point().to_path_buf();
std::fs::write(mp.join("hello.txt"), "world").unwrap();
// 4. Unmount and decide what to do with the changes.
overlay.umount();
overlay.overlay_action(OverlayAction::Commit); // merges upper โ lower
```
### ๐ Custom upper path
```rust
let mut overlay = OverlayFS::new(PathBuf::from("/data/base"));
overlay.set_upper(PathBuf::from("/data/session-changes"));
overlay.mount().unwrap();
```
### ๐งฑ Persistent inodes
```rust
use overlay_fuse::InodeMode;
let mut overlay = OverlayFS::new(PathBuf::from("/opt/rootfs"));
overlay.set_inode_mode(InodeMode::Persistent);
overlay.mount().unwrap();
```
## ๐ OverlayAction Reference
| `Preserve` | Upper layer kept on disk; mount point removed. |
| `Discard` | Upper layer and mount point deleted entirely. |
| `Commit` | Upper merged into lower (whiteouts processed); both cleaned up. |
| `CommitAtomic` | Backup-and-swap merge; upper removed only after successful write. |
## ๐ Path Conventions
Given `OverlayFS::new(PathBuf::from("/base/lower"))`:
| Lower (read-only) | `/base/lower` |
| Upper (read-write) | `/base/lower.upper` |
| Mount point | `/base/lower.mountpoint` |
Override the upper path with `set_upper()` before calling `mount()`.
## ๐ Project Structure
```
src/
โโโ lib.rs # Public API re-exports
โโโ overlay.rs # OverlayFS controller, commit strategies, xattr utilities
โโโ layers.rs # LayerManager: resolve, CoW, whiteout management
โโโ inode.rs # InodeStore: thread-safe inode โ path mapping
โโโ files.rs # OverlayFiles: layer path configuration
โโโ fuse_ops.rs # FUSE operation handlers
```
## ๐ MIT License
This repository has scripts that were created to be free software.
Therefore, they can be distributed and/or modified within the terms of the ***MIT License***.
> ### See the [LICENSE](LICENSE) file for details.
## ๐ฌ Contact & Support
* ๐ง **Email:** [m10ferrari1200@gmail.com](mailto:m10ferrari1200@gmail.com)
* ๐ง **Email:** [contatolinuxdicaspro@gmail.com](mailto:contatolinuxdicaspro@gmail.com)