use crate::db::{DbConn, DbTransaction, TransactionBehavior};
use crate::error::Result;
use std::time::{SystemTime, UNIX_EPOCH};
use super::DEFAULT_DIR_MODE;
pub async fn ensure(conn: &DbConn, id: &str) -> Result<i64> {
let mut rows = conn
.query("SELECT root_ino FROM fs_volumes WHERE id = ?", (id,))
.await?;
if let Some(row) = rows.next().await? {
let ino = row.get_value(0)?;
return Ok(*ino.as_integer().expect("root_ino is an integer"));
}
let tx = DbTransaction::new_unchecked(conn, TransactionBehavior::Deferred).await?;
let dur = SystemTime::now().duration_since(UNIX_EPOCH)?;
let now_secs = dur.as_secs() as i64;
let now_nsec = dur.subsec_nanos() as i64;
let (uid, gid) = unsafe { (libc::getuid() as i64, libc::getgid() as i64) };
let mut ino_rows = conn
.query(
"INSERT INTO fs_inode \
(mode, nlink, uid, gid, size, atime, mtime, ctime, atime_nsec, mtime_nsec, ctime_nsec) \
VALUES (?, 2, ?, ?, 0, ?, ?, ?, ?, ?, ?) \
RETURNING ino",
(
DEFAULT_DIR_MODE as i64,
uid,
gid,
now_secs,
now_secs,
now_secs,
now_nsec,
now_nsec,
now_nsec,
),
)
.await?;
let ino_row = ino_rows
.next()
.await?
.expect("INSERT ... RETURNING ino must return a row");
let root_ino = *ino_row
.get_value(0)?
.as_integer()
.expect("ino is an integer");
conn.execute(
"INSERT INTO fs_dentry (name, parent_ino, ino) VALUES (?, 1, ?)",
(id, root_ino),
)
.await?;
conn.execute(
"INSERT INTO fs_volumes (id, root_ino) VALUES (?, ?)",
(id, root_ino),
)
.await?;
tx.commit().await?;
Ok(root_ino)
}
pub async fn destroy(conn: &DbConn, id: &str) -> Result<bool> {
let mut rows = conn
.query("SELECT root_ino FROM fs_volumes WHERE id = ?", (id,))
.await?;
let root_ino = match rows.next().await? {
None => return Ok(false),
Some(row) => *row.get_value(0)?.as_integer().expect("root_ino is an integer"),
};
conn.execute("DELETE FROM fs_volumes WHERE id = ?", (id,))
.await?;
conn.execute(
"DELETE FROM fs_dentry WHERE parent_ino = 1 AND ino = ?",
(root_ino,),
)
.await?;
conn.execute(
"WITH RECURSIVE subtree(ino) AS (
SELECT ?::bigint \
UNION ALL \
SELECT d.ino FROM fs_dentry d JOIN subtree s ON d.parent_ino = s.ino
)
DELETE FROM fs_data WHERE ino IN (SELECT ino FROM subtree)",
(root_ino,),
)
.await?;
conn.execute(
"WITH RECURSIVE subtree(ino) AS (
SELECT ?::bigint \
UNION ALL \
SELECT d.ino FROM fs_dentry d JOIN subtree s ON d.parent_ino = s.ino
)
DELETE FROM fs_symlink WHERE ino IN (SELECT ino FROM subtree)",
(root_ino,),
)
.await?;
conn.execute(
"WITH RECURSIVE subtree(ino) AS (
SELECT ?::bigint \
UNION ALL \
SELECT d.ino FROM fs_dentry d JOIN subtree s ON d.parent_ino = s.ino
)
DELETE FROM fs_inode WHERE ino IN (SELECT ino FROM subtree)",
(root_ino,),
)
.await?;
conn.execute(
"WITH RECURSIVE subtree(ino) AS (
SELECT ?::bigint \
UNION ALL \
SELECT d.ino FROM fs_dentry d JOIN subtree s ON d.parent_ino = s.ino
)
DELETE FROM fs_dentry WHERE ino IN (SELECT ino FROM subtree)
OR parent_ino IN (SELECT ino FROM subtree)",
(root_ino,),
)
.await?;
Ok(true)
}