Skip to main content

embeddenator_cli/commands/
mount.rs

1//! FUSE mount command implementation
2
3#[cfg(feature = "fuse")]
4use anyhow::Result;
5#[cfg(feature = "fuse")]
6use embeddenator_fs::embrfs::{EmbrFS, DEFAULT_CHUNK_SIZE};
7#[cfg(feature = "fuse")]
8use embeddenator_fs::fuse_shim::{mount, EngramFS, MountOptions};
9#[cfg(feature = "fuse")]
10use embeddenator_vsa::ReversibleVSAConfig;
11#[cfg(feature = "fuse")]
12use std::path::PathBuf;
13
14#[cfg(feature = "fuse")]
15pub fn handle_mount(
16    engram: PathBuf,
17    manifest: PathBuf,
18    mountpoint: PathBuf,
19    allow_other: bool,
20    _foreground: bool,
21    verbose: bool,
22) -> Result<()> {
23    if verbose {
24        println!("Embeddenator v{} - FUSE Mount", env!("CARGO_PKG_VERSION"));
25        println!("============================");
26    }
27
28    // Load engram and manifest
29    let engram_data = EmbrFS::load_engram(&engram)?;
30    let manifest_data = EmbrFS::load_manifest(&manifest)?;
31    let config = ReversibleVSAConfig::default();
32
33    if verbose {
34        println!("Loaded engram: {}", engram.display());
35        println!("Loaded manifest: {} files", manifest_data.files.len());
36    }
37
38    // Create FUSE filesystem and populate with decoded files
39    let fuse_fs = EngramFS::new(true);
40
41    for file_entry in &manifest_data.files {
42        // Decode file data using the same approach as EmbrFS::extract
43        let mut reconstructed = Vec::new();
44
45        for &chunk_id in &file_entry.chunks {
46            if let Some(chunk_vec) = engram_data.codebook.get(&chunk_id) {
47                // Decode the sparse vector to bytes
48                // IMPORTANT: Use the same path as during encoding for correct shift calculation
49                let decoded =
50                    chunk_vec.decode_data(&config, Some(&file_entry.path), DEFAULT_CHUNK_SIZE);
51
52                // Apply correction to guarantee bit-perfect reconstruction
53                let chunk_data = if let Some(corrected) =
54                    engram_data.corrections.apply(chunk_id as u64, &decoded)
55                {
56                    corrected
57                } else {
58                    // No correction found - use decoded directly
59                    decoded
60                };
61
62                reconstructed.extend_from_slice(&chunk_data);
63            }
64        }
65
66        // Truncate to exact file size
67        reconstructed.truncate(file_entry.size);
68
69        // Add to FUSE filesystem
70        if let Err(e) = fuse_fs.add_file(&file_entry.path, reconstructed) {
71            if verbose {
72                eprintln!("Warning: Failed to add {}: {}", file_entry.path, e);
73            }
74        }
75    }
76
77    if verbose {
78        println!(
79            "Populated {} files into FUSE filesystem",
80            fuse_fs.file_count()
81        );
82        println!("Total size: {} bytes", fuse_fs.total_size());
83        println!("Mounting at: {}", mountpoint.display());
84        println!();
85    }
86
87    // Verify mountpoint exists
88    if !mountpoint.exists() {
89        anyhow::bail!("Mountpoint does not exist: {}", mountpoint.display());
90    }
91
92    // Configure mount options
93    let options = MountOptions {
94        read_only: true,
95        allow_other,
96        allow_root: !allow_other,
97        fsname: format!("engram:{}", engram.display()),
98    };
99
100    // Mount the filesystem (blocks until unmounted)
101    println!("EngramFS mounted at {}", mountpoint.display());
102    println!("Use 'fusermount -u {}' to unmount", mountpoint.display());
103
104    mount(fuse_fs, &mountpoint, options)?;
105
106    if verbose {
107        println!("\nUnmounted.");
108    }
109
110    Ok(())
111}
112
113#[cfg(not(feature = "fuse"))]
114pub fn handle_mount(
115    _engram: std::path::PathBuf,
116    _manifest: std::path::PathBuf,
117    _mountpoint: std::path::PathBuf,
118    _allow_other: bool,
119    _foreground: bool,
120    _verbose: bool,
121) -> anyhow::Result<()> {
122    anyhow::bail!("FUSE support not enabled. Build with --features fuse")
123}