Skip to content

Commit d7e8f05

Browse files
authored
cli: Fix overlay mount I/O error by unifying whiteout schema in SDK (#125)
The whiteout table created by `agentfs init --base` was missing the `parent_path` column that `overlayfs.rs` queries during directory listing. This caused `get_child_whiteouts()` to fail with a SQL error, which propagated as an I/O error when running `ls` on the mounted filesystem. The fix moves the schema definition to a single location in the SDK (`OverlayFS::init_schema`) to prevent future drift between CLI and SDK. The CLI now calls this method instead of duplicating the SQL. Also removes dead `base_type` code that was set but never read. Fixes #106
2 parents 27b4c58 + 0d42d97 commit d7e8f05

2 files changed

Lines changed: 23 additions & 46 deletions

File tree

cli/src/cmd/init.rs

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::path::PathBuf;
22
use std::time::{SystemTime, UNIX_EPOCH};
33

4-
use agentfs_sdk::{agentfs_dir, AgentFS, AgentFSOptions};
4+
use agentfs_sdk::{agentfs_dir, AgentFS, AgentFSOptions, OverlayFS};
55
use anyhow::{Context, Result as AnyhowResult};
66

77
pub async fn init_database(
@@ -63,52 +63,18 @@ pub async fn init_database(
6363
.await
6464
.context("Failed to initialize database")?;
6565

66-
// If base is provided, store the overlay configuration
66+
// If base is provided, initialize the overlay schema using the SDK
6767
if let Some(base_path) = base {
68-
let conn = agent.get_connection();
69-
70-
// Create whiteout table for overlay support
71-
conn.execute(
72-
"CREATE TABLE IF NOT EXISTS fs_whiteout (
73-
path TEXT PRIMARY KEY,
74-
created_at INTEGER NOT NULL
75-
)",
76-
(),
77-
)
78-
.await
79-
.context("Failed to create whiteout table")?;
80-
81-
// Create overlay config table
82-
conn.execute(
83-
"CREATE TABLE IF NOT EXISTS fs_overlay_config (
84-
key TEXT PRIMARY KEY,
85-
value TEXT NOT NULL
86-
)",
87-
(),
88-
)
89-
.await
90-
.context("Failed to create overlay config table")?;
91-
92-
// Store base path configuration
9368
let base_path_str = base_path
9469
.canonicalize()
9570
.context("Failed to canonicalize base path")?
9671
.to_string_lossy()
9772
.to_string();
9873

99-
conn.execute(
100-
"INSERT INTO fs_overlay_config (key, value) VALUES ('base_type', 'hostfs')",
101-
(),
102-
)
103-
.await
104-
.context("Failed to store base type")?;
105-
106-
conn.execute(
107-
"INSERT INTO fs_overlay_config (key, value) VALUES ('base_path', ?)",
108-
(base_path_str.as_str(),),
109-
)
110-
.await
111-
.context("Failed to store base path")?;
74+
// Use SDK's OverlayFS::init_schema to ensure schema consistency
75+
OverlayFS::init_schema(&agent.get_connection(), &base_path_str)
76+
.await
77+
.context("Failed to initialize overlay schema")?;
11278

11379
eprintln!("Created overlay filesystem: {}", db_path.display());
11480
eprintln!("Agent ID: {}", id);

sdk/rust/src/filesystem/overlayfs.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::{
55
sync::Arc,
66
time::{SystemTime, UNIX_EPOCH},
77
};
8-
use turso::Value;
8+
use turso::{Connection, Value};
99

1010
use super::{agentfs::AgentFS, DirEntry, FileSystem, FilesystemStats, FsError, Stats};
1111

@@ -38,16 +38,15 @@ impl OverlayFS {
3838
Self { base, delta }
3939
}
4040

41-
/// Initialize the overlay filesystem schema (creates whiteout table)
41+
/// Initialize the overlay filesystem schema in a database.
4242
///
43-
/// This must be called before using the overlay filesystem to ensure
44-
/// the whiteout tracking table exists in the delta layer.
43+
/// This is a static method that can be called without creating an OverlayFS
44+
/// instance, useful for CLI tools that need to initialize an overlay database.
4545
///
4646
/// The `base_path` parameter specifies the actual filesystem path that the
4747
/// base layer represents. This is stored in the delta database so that
4848
/// tools like `agentfs diff` can determine what files were modified.
49-
pub async fn init(&self, base_path: &str) -> Result<()> {
50-
let conn = self.delta.get_connection();
49+
pub async fn init_schema(conn: &Connection, base_path: &str) -> Result<()> {
5150
conn.execute(
5251
"CREATE TABLE IF NOT EXISTS fs_whiteout (
5352
path TEXT PRIMARY KEY,
@@ -80,6 +79,18 @@ impl OverlayFS {
8079
Ok(())
8180
}
8281

82+
/// Initialize the overlay filesystem schema (creates whiteout table)
83+
///
84+
/// This must be called before using the overlay filesystem to ensure
85+
/// the whiteout tracking table exists in the delta layer.
86+
///
87+
/// The `base_path` parameter specifies the actual filesystem path that the
88+
/// base layer represents. This is stored in the delta database so that
89+
/// tools like `agentfs diff` can determine what files were modified.
90+
pub async fn init(&self, base_path: &str) -> Result<()> {
91+
Self::init_schema(&self.delta.get_connection(), base_path).await
92+
}
93+
8394
/// Extract the parent path from a normalized path
8495
fn parent_path(path: &str) -> String {
8596
if path == "/" {

0 commit comments

Comments
 (0)