summaryrefslogtreecommitdiff
path: root/src/generation.rs
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2020-11-10 07:30:32 +0200
committerLars Wirzenius <liw@liw.fi>2020-11-10 10:46:07 +0200
commit6a5a9854eb90b767b668403928e2c64091929b51 (patch)
treee17847eea9be6df26da86669008185b2ac2ec967 /src/generation.rs
parent6707f65cc6152bc1a5f54331e921d4fac5f597fc (diff)
downloadobnam2-6a5a9854eb90b767b668403928e2c64091929b51.tar.gz
feat: restore a generation
Diffstat (limited to 'src/generation.rs')
-rw-r--r--src/generation.rs62
1 files changed, 57 insertions, 5 deletions
diff --git a/src/generation.rs b/src/generation.rs
index ca1f8d5..b9edb74 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -1,9 +1,11 @@
-use crate::fsentry::FilesystemEntry;
+use crate::fsentry::{FilesystemEntry, FilesystemKind};
+use std::ffi::OsStr;
+use std::os::unix::ffi::OsStrExt;
//use crate::fsiter::FsIterator;
use crate::chunkid::ChunkId;
-use rusqlite::{params, Connection, OpenFlags, Transaction};
+use rusqlite::{params, Connection, OpenFlags, Row, Transaction};
use std::os::unix::ffi::OsStringExt;
-use std::path::Path;
+use std::path::{Path, PathBuf};
/// A backup generation.
pub struct Generation {
@@ -12,7 +14,7 @@ pub struct Generation {
}
impl Generation {
- pub fn new<P>(filename: P) -> anyhow::Result<Self>
+ pub fn create<P>(filename: P) -> anyhow::Result<Self>
where
P: AsRef<Path>,
{
@@ -30,6 +32,16 @@ impl Generation {
Ok(Self { conn, fileno: 0 })
}
+ pub fn open<P>(filename: P) -> anyhow::Result<Self>
+ where
+ P: AsRef<Path>,
+ {
+ let flags = OpenFlags::SQLITE_OPEN_READ_WRITE;
+ let conn = Connection::open_with_flags(filename, flags)?;
+ conn.pragma_update(None, "journal_mode", &"WAL")?;
+ Ok(Self { conn, fileno: 0 })
+ }
+
pub fn insert(&mut self, e: FilesystemEntry, ids: &[ChunkId]) -> anyhow::Result<()> {
let t = self.conn.transaction()?;
insert_one(&t, e, self.fileno, ids)?;
@@ -51,6 +63,46 @@ impl Generation {
t.commit()?;
Ok(())
}
+
+ pub fn files(&self) -> anyhow::Result<Vec<(u64, FilesystemEntry)>> {
+ let mut stmt = self.conn.prepare("SELECT * FROM files")?;
+ let iter = stmt.query_map(params![], |row| row_to_entry(row))?;
+ let mut files: Vec<(u64, FilesystemEntry)> = vec![];
+ for x in iter {
+ let (fileid, entry) = x?;
+ files.push((fileid, entry));
+ }
+ Ok(files)
+ }
+
+ pub fn chunkids(&self, fileid: u64) -> anyhow::Result<Vec<ChunkId>> {
+ let fileid = fileid as i64;
+ let mut stmt = self
+ .conn
+ .prepare("SELECT chunkid FROM chunks WHERE fileid = ?1")?;
+ let iter = stmt.query_map(params![fileid], |row| Ok(row.get(0)?))?;
+ let mut ids: Vec<ChunkId> = vec![];
+ for x in iter {
+ let fileid: String = x?;
+ ids.push(ChunkId::from(&fileid));
+ }
+ Ok(ids)
+ }
+}
+
+fn row_to_entry(row: &Row) -> rusqlite::Result<(u64, FilesystemEntry)> {
+ let fileid: i64 = row.get(row.column_index("fileid")?)?;
+ let fileid = fileid as u64;
+ let path: Vec<u8> = row.get(row.column_index("path")?)?;
+ let path: &OsStr = OsStrExt::from_bytes(&path);
+ let path: PathBuf = PathBuf::from(path);
+ let kind = row.get(row.column_index("kind")?)?;
+ let kind = FilesystemKind::from_code(kind).unwrap();
+ let entry = match kind {
+ FilesystemKind::Regular => FilesystemEntry::regular(path, 0),
+ FilesystemKind::Directory => FilesystemEntry::directory(path),
+ };
+ Ok((fileid, entry))
}
fn insert_one(
@@ -85,7 +137,7 @@ mod test {
fn empty() {
let filename = NamedTempFile::new().unwrap().path().to_path_buf();
{
- let mut _gen = Generation::new(&filename).unwrap();
+ let mut _gen = Generation::create(&filename).unwrap();
// _gen is dropped here; the connection is close; the file
// should not be removed.
}