chore: format the pinned content history foundation
Only rustfmt normalization of exact T835 dependency snapshot 223aa125de. Diff reviewed: whitespace and optional trailing-comma changes only; string literal sequences unchanged. No semantic fixes, manifests or lock changes adopted from the in-progress branch.
This commit is contained in:
@@ -174,7 +174,10 @@ fn restore_directory(
|
|||||||
// A valid directory must lead to an as-yet unrestored metadata entry. This also
|
// A valid directory must lead to an as-yet unrestored metadata entry. This also
|
||||||
// bounds traversal of adversarial shared subtrees by the existing entry/path limits.
|
// bounds traversal of adversarial shared subtrees by the existing entry/path limits.
|
||||||
let child_prefix = format!("{path}/");
|
let child_prefix = format!("{path}/");
|
||||||
if !metadata.keys().any(|key| key.as_str().starts_with(&child_prefix)) {
|
if !metadata
|
||||||
|
.keys()
|
||||||
|
.any(|key| key.as_str().starts_with(&child_prefix))
|
||||||
|
{
|
||||||
return Err(Error::Structure("config directory has no file metadata"));
|
return Err(Error::Structure("config directory has no file metadata"));
|
||||||
}
|
}
|
||||||
restore_directory(child, path.as_str(), read, metadata, entries, total)?
|
restore_directory(child, path.as_str(), read, metadata, entries, total)?
|
||||||
|
|||||||
@@ -64,16 +64,23 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn authorize(&self, access: Access) -> Result<()> {
|
fn authorize(&self, access: Access) -> Result<()> {
|
||||||
if self.key.workspace.is_empty() || self.key.target.is_empty()
|
if self.key.workspace.is_empty()
|
||||||
|
|| self.key.target.is_empty()
|
||||||
|| !self.authority.allows(&self.key, access)
|
|| !self.authority.allows(&self.key, access)
|
||||||
{
|
{
|
||||||
return Err(Error::Denied);
|
return Err(Error::Denied);
|
||||||
}
|
}
|
||||||
let erased: Option<bool> = self.tx.query_row(
|
let erased: Option<bool> = self
|
||||||
"SELECT erased FROM content_scopes WHERE workspace=?1 AND target=?2",
|
.tx
|
||||||
params![self.key.workspace, self.key.target], |r| r.get(0),
|
.query_row(
|
||||||
).optional()?;
|
"SELECT erased FROM content_scopes WHERE workspace=?1 AND target=?2",
|
||||||
if erased == Some(true) { return Err(Error::Erased); }
|
params![self.key.workspace, self.key.target],
|
||||||
|
|r| r.get(0),
|
||||||
|
)
|
||||||
|
.optional()?;
|
||||||
|
if erased == Some(true) {
|
||||||
|
return Err(Error::Erased);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,12 +98,21 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn head_inner(&self) -> Result<Option<HistoryId>> {
|
fn head_inner(&self) -> Result<Option<HistoryId>> {
|
||||||
let raw: Option<Vec<u8>> = self.tx.query_row(
|
let raw: Option<Vec<u8>> = self
|
||||||
"SELECT head FROM content_scopes WHERE workspace=?1 AND target=?2",
|
.tx
|
||||||
params![self.key.workspace, self.key.target], |r| r.get(0),
|
.query_row(
|
||||||
).optional()?.flatten();
|
"SELECT head FROM content_scopes WHERE workspace=?1 AND target=?2",
|
||||||
raw.map(|v| Ok(HistoryId::from_bytes(v.try_into().map_err(|_| Error::InvalidReference)?)))
|
params![self.key.workspace, self.key.target],
|
||||||
.transpose()
|
|r| r.get(0),
|
||||||
|
)
|
||||||
|
.optional()?
|
||||||
|
.flatten();
|
||||||
|
raw.map(|v| {
|
||||||
|
Ok(HistoryId::from_bytes(
|
||||||
|
v.try_into().map_err(|_| Error::InvalidReference)?,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preparation requires the full canonical bytes, not possession of another scope's hash.
|
/// Preparation requires the full canonical bytes, not possession of another scope's hash.
|
||||||
@@ -110,11 +126,18 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
fn put_inner(&self, id: ObjectId, bytes: &[u8]) -> Result<()> {
|
fn put_inner(&self, id: ObjectId, bytes: &[u8]) -> Result<()> {
|
||||||
self.ensure_scope()?;
|
self.ensure_scope()?;
|
||||||
let (kind, hash) = parts(id);
|
let (kind, hash) = parts(id);
|
||||||
self.tx.execute("INSERT OR IGNORE INTO content_objects(kind,hash,bytes) VALUES(?1,?2,?3)",
|
self.tx.execute(
|
||||||
params![kind, hash, bytes])?;
|
"INSERT OR IGNORE INTO content_objects(kind,hash,bytes) VALUES(?1,?2,?3)",
|
||||||
|
params![kind, hash, bytes],
|
||||||
|
)?;
|
||||||
let stored: Vec<u8> = self.tx.query_row(
|
let stored: Vec<u8> = self.tx.query_row(
|
||||||
"SELECT bytes FROM content_objects WHERE kind=?1 AND hash=?2", params![kind, hash], |r| r.get(0))?;
|
"SELECT bytes FROM content_objects WHERE kind=?1 AND hash=?2",
|
||||||
if stored != bytes { return Err(Error::ImmutableMismatch); }
|
params![kind, hash],
|
||||||
|
|r| r.get(0),
|
||||||
|
)?;
|
||||||
|
if stored != bytes {
|
||||||
|
return Err(Error::ImmutableMismatch);
|
||||||
|
}
|
||||||
self.tx.execute("INSERT OR IGNORE INTO content_scope_objects(workspace,target,kind,hash) VALUES(?1,?2,?3,?4)",
|
self.tx.execute("INSERT OR IGNORE INTO content_scope_objects(workspace,target,kind,hash) VALUES(?1,?2,?3,?4)",
|
||||||
params![self.key.workspace, self.key.target, kind, hash])?;
|
params![self.key.workspace, self.key.target, kind, hash])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -128,7 +151,9 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
let allowed: bool = self.tx.query_row(
|
let allowed: bool = self.tx.query_row(
|
||||||
"SELECT EXISTS(SELECT 1 FROM content_reachable WHERE workspace=?1 AND target=?2 AND kind=?3 AND hash=?4)",
|
"SELECT EXISTS(SELECT 1 FROM content_reachable WHERE workspace=?1 AND target=?2 AND kind=?3 AND hash=?4)",
|
||||||
params![self.key.workspace, self.key.target, kind, hash], |r| r.get(0))?;
|
params![self.key.workspace, self.key.target, kind, hash], |r| r.get(0))?;
|
||||||
if !allowed { return Err(Error::Unavailable); }
|
if !allowed {
|
||||||
|
return Err(Error::Unavailable);
|
||||||
|
}
|
||||||
self.load_prepared(id)
|
self.load_prepared(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,18 +174,32 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
self.walk([ObjectId::Tree(record.root)], true)
|
self.walk([ObjectId::Tree(record.root)], true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk(&self, roots: impl IntoIterator<Item=ObjectId>, public: bool) -> Result<BTreeMap<ObjectId, Object>> {
|
fn walk(
|
||||||
|
&self,
|
||||||
|
roots: impl IntoIterator<Item = ObjectId>,
|
||||||
|
public: bool,
|
||||||
|
) -> Result<BTreeMap<ObjectId, Object>> {
|
||||||
let mut pending: Vec<_> = roots.into_iter().collect();
|
let mut pending: Vec<_> = roots.into_iter().collect();
|
||||||
let mut objects = BTreeMap::new();
|
let mut objects = BTreeMap::new();
|
||||||
while let Some(id) = pending.pop() {
|
while let Some(id) = pending.pop() {
|
||||||
if objects.contains_key(&id) { continue; }
|
if objects.contains_key(&id) {
|
||||||
let object = if public { self.read(id)? } else { self.load_prepared(id)? };
|
continue;
|
||||||
|
}
|
||||||
|
let object = if public {
|
||||||
|
self.read(id)?
|
||||||
|
} else {
|
||||||
|
self.load_prepared(id)?
|
||||||
|
};
|
||||||
match &object {
|
match &object {
|
||||||
Object::Blob(_) => {},
|
Object::Blob(_) => {}
|
||||||
Object::Tree(tree) => pending.extend(tree.entries().iter().map(|e| ObjectId::from(e.target))),
|
Object::Tree(tree) => {
|
||||||
|
pending.extend(tree.entries().iter().map(|e| ObjectId::from(e.target)))
|
||||||
|
}
|
||||||
Object::History(history) => {
|
Object::History(history) => {
|
||||||
pending.push(ObjectId::Tree(history.root));
|
pending.push(ObjectId::Tree(history.root));
|
||||||
if let Some(parent) = history.parent { pending.push(ObjectId::History(parent)); }
|
if let Some(parent) = history.parent {
|
||||||
|
pending.push(ObjectId::History(parent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
objects.insert(id, object);
|
objects.insert(id, object);
|
||||||
@@ -171,7 +210,13 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
/// Authenticated actor and clock facts belong to the caller, not restored post authors.
|
/// Authenticated actor and clock facts belong to the caller, not restored post authors.
|
||||||
/// Restoring an old root appends a history with the current parent; no rewind operation exists.
|
/// Restoring an old root appends a history with the current parent; no rewind operation exists.
|
||||||
/// The private savepoint prevents even a caught error from publishing a partial adoption.
|
/// The private savepoint prevents even a caught error from publishing a partial adoption.
|
||||||
pub fn adopt(&self, root: TreeId, expected: Option<HistoryId>, actor: String, timestamp_micros: i64) -> Result<HistoryId> {
|
pub fn adopt(
|
||||||
|
&self,
|
||||||
|
root: TreeId,
|
||||||
|
expected: Option<HistoryId>,
|
||||||
|
actor: String,
|
||||||
|
timestamp_micros: i64,
|
||||||
|
) -> Result<HistoryId> {
|
||||||
self.authorize(Access::Write)?;
|
self.authorize(Access::Write)?;
|
||||||
self.atomic(|| {
|
self.atomic(|| {
|
||||||
if self.head_inner()? != expected { return Err(Error::Conflict); }
|
if self.head_inner()? != expected { return Err(Error::Conflict); }
|
||||||
@@ -215,9 +260,18 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
self.authorize(Access::Erase)?;
|
self.authorize(Access::Erase)?;
|
||||||
self.atomic(|| {
|
self.atomic(|| {
|
||||||
self.ensure_scope()?;
|
self.ensure_scope()?;
|
||||||
self.tx.execute("DELETE FROM content_reachable WHERE workspace=?1 AND target=?2", params![self.key.workspace,self.key.target])?;
|
self.tx.execute(
|
||||||
self.tx.execute("DELETE FROM content_scope_objects WHERE workspace=?1 AND target=?2", params![self.key.workspace,self.key.target])?;
|
"DELETE FROM content_reachable WHERE workspace=?1 AND target=?2",
|
||||||
self.tx.execute("UPDATE content_scopes SET head=NULL,erased=1 WHERE workspace=?1 AND target=?2", params![self.key.workspace,self.key.target])?;
|
params![self.key.workspace, self.key.target],
|
||||||
|
)?;
|
||||||
|
self.tx.execute(
|
||||||
|
"DELETE FROM content_scope_objects WHERE workspace=?1 AND target=?2",
|
||||||
|
params![self.key.workspace, self.key.target],
|
||||||
|
)?;
|
||||||
|
self.tx.execute(
|
||||||
|
"UPDATE content_scopes SET head=NULL,erased=1 WHERE workspace=?1 AND target=?2",
|
||||||
|
params![self.key.workspace, self.key.target],
|
||||||
|
)?;
|
||||||
self.collect_physical()
|
self.collect_physical()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -227,12 +281,18 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atomic<T>(&self, f: impl FnOnce()->Result<T>) -> Result<T> {
|
fn atomic<T>(&self, f: impl FnOnce() -> Result<T>) -> Result<T> {
|
||||||
self.tx.execute_batch("SAVEPOINT content_history_operation")?;
|
self.tx
|
||||||
|
.execute_batch("SAVEPOINT content_history_operation")?;
|
||||||
match f() {
|
match f() {
|
||||||
Ok(value) => { self.tx.execute_batch("RELEASE content_history_operation")?; Ok(value) },
|
Ok(value) => {
|
||||||
|
self.tx.execute_batch("RELEASE content_history_operation")?;
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
self.tx.execute_batch("ROLLBACK TO content_history_operation; RELEASE content_history_operation")?;
|
self.tx.execute_batch(
|
||||||
|
"ROLLBACK TO content_history_operation; RELEASE content_history_operation",
|
||||||
|
)?;
|
||||||
Err(error)
|
Err(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,8 +301,8 @@ impl<'a, 'conn> ScopedStore<'a, 'conn> {
|
|||||||
|
|
||||||
fn parts(id: ObjectId) -> (u8, Vec<u8>) {
|
fn parts(id: ObjectId) -> (u8, Vec<u8>) {
|
||||||
match id {
|
match id {
|
||||||
ObjectId::Blob(h) => (1,h.as_bytes().to_vec()),
|
ObjectId::Blob(h) => (1, h.as_bytes().to_vec()),
|
||||||
ObjectId::Tree(h) => (2,h.as_bytes().to_vec()),
|
ObjectId::Tree(h) => (2, h.as_bytes().to_vec()),
|
||||||
ObjectId::History(h) => (3,h.as_bytes().to_vec()),
|
ObjectId::History(h) => (3, h.as_bytes().to_vec()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user