From 9328adfaf9fd532b72b482a9dfd2ee675a68831d Mon Sep 17 00:00:00 2001 From: "Zeyi (Rice) Fan" Date: Tue, 19 Nov 2019 17:56:59 -0800 Subject: [PATCH] backingstore: add `Tree` and `TreeEntry` Rust structs to pass manifest Summary: This diff adds Rust structs to represent the data EdenFS wants from a manifest so we can pass these to EdenFS. Reviewed By: wez Differential Revision: D18365440 fbshipit-source-id: b474ceb698d9230e1b02c2cce1bec2a32bd3f94f --- .../lib/backingstore/c_api/RustBackingStore.h | 25 ++++- eden/scm/lib/backingstore/cbindgen.toml | 1 + eden/scm/lib/backingstore/src/raw/mod.rs | 2 + eden/scm/lib/backingstore/src/raw/tree.rs | 105 ++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 eden/scm/lib/backingstore/src/raw/tree.rs diff --git a/eden/scm/lib/backingstore/c_api/RustBackingStore.h b/eden/scm/lib/backingstore/c_api/RustBackingStore.h index f3af97c2c6..8ee9e5695c 100644 --- a/eden/scm/lib/backingstore/c_api/RustBackingStore.h +++ b/eden/scm/lib/backingstore/c_api/RustBackingStore.h @@ -7,7 +7,7 @@ * This file is generated with cbindgen. Please run `./tools/cbindgen.sh` to * update this file. * - * @generated SignedSource<<9e8a2dc050438223b658363f7614992e>> + * @generated SignedSource<> * */ @@ -76,6 +76,13 @@ public: #include #include +enum class RustTreeEntryType : uint8_t { + Tree, + RegularFile, + ExecutableFile, + Symlink, +}; + struct RustBackingStore; template @@ -94,6 +101,22 @@ operator folly::ByteRange() const { } }; +struct RustTreeEntry { + RustCBytes hash; + RustCBytes name; + RustTreeEntryType ttype; + uint64_t *size; + RustCBytes *content_sha1; +}; + +struct RustTree { + const RustTreeEntry *entries; + /// This makes sure `entries` above is pointing to a valid memory. + RustVec *_entries; + uintptr_t length; + RustCBytes hash; +}; + extern "C" { void rust_backingstore_free(RustBackingStore *store); diff --git a/eden/scm/lib/backingstore/cbindgen.toml b/eden/scm/lib/backingstore/cbindgen.toml index a1a5b28151..00dd70d8e2 100644 --- a/eden/scm/lib/backingstore/cbindgen.toml +++ b/eden/scm/lib/backingstore/cbindgen.toml @@ -78,6 +78,7 @@ public: [export] prefix= "Rust" exclude = ["CFallible"] +include = ["Tree", "TreeEntry", "TreeEntryType"] [export.rename] "CFallible" = "CFallibleBase" diff --git a/eden/scm/lib/backingstore/src/raw/mod.rs b/eden/scm/lib/backingstore/src/raw/mod.rs index 24bacdd1dd..c3e948600f 100644 --- a/eden/scm/lib/backingstore/src/raw/mod.rs +++ b/eden/scm/lib/backingstore/src/raw/mod.rs @@ -14,6 +14,8 @@ mod backingstore; mod cbytes; mod cfallible; mod tests; +mod tree; pub use cbytes::CBytes; pub use cfallible::CFallible; +pub use tree::Tree; diff --git a/eden/scm/lib/backingstore/src/raw/tree.rs b/eden/scm/lib/backingstore/src/raw/tree.rs new file mode 100644 index 0000000000..54efc64170 --- /dev/null +++ b/eden/scm/lib/backingstore/src/raw/tree.rs @@ -0,0 +1,105 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This software may be used and distributed according to the terms of the + * GNU General Public License version 2. + */ + +//! Representation of tree in EdenFS. +//! +//! Structs in this file should be keep in sync with `eden/fs/model/{Tree, TreeEntry}.h`. + +use crate::raw::CBytes; +use failure::{format_err, Fallible}; +use manifest::{tree::List, FileType, FsNode}; +use std::convert::TryFrom; +use types::PathComponentBuf; + +#[repr(u8)] +pub enum TreeEntryType { + Tree, + RegularFile, + ExecutableFile, + Symlink, +} + +impl From for TreeEntryType { + fn from(file_type: FileType) -> Self { + match file_type { + FileType::Regular => TreeEntryType::RegularFile, + FileType::Executable => TreeEntryType::ExecutableFile, + FileType::Symlink => TreeEntryType::Symlink, + } + } +} + +#[repr(C)] +pub struct TreeEntry { + hash: CBytes, + name: CBytes, + ttype: TreeEntryType, + // Using pointer as `Option` + size: *mut u64, + content_sha1: *mut CBytes, +} + +impl TreeEntry { + fn try_from_path_node(path: PathComponentBuf, node: FsNode) -> Fallible { + let (ttype, hash) = match node { + FsNode::Directory(Some(hgid)) => (TreeEntryType::Tree, hgid.as_ref().to_vec()), + FsNode::File(metadata) => (metadata.file_type.into(), metadata.hgid.as_ref().to_vec()), + _ => return Err(format_err!("received an ephemeral directory")), + }; + + Ok(TreeEntry { + hash: hash.into(), + name: path.as_ref().as_byte_slice().to_vec().into(), + ttype, + // TODO: we currently do not have these information stored in Mercurial. + size: std::ptr::null_mut(), + content_sha1: std::ptr::null_mut(), + }) + } +} + +#[repr(C)] +pub struct Tree { + entries: *const TreeEntry, + /// This makes sure `entries` above is pointing to a valid memory. + entries_ptr: *mut Vec, + length: usize, + hash: CBytes, +} + +impl TryFrom for Tree { + type Error = failure::Error; + + fn try_from(list: List) -> Result { + match list { + List::NotFound | List::File => Err(format_err!("not found")), + List::Directory(list) => { + let entries = list + .into_iter() + .map(|(path, node)| TreeEntry::try_from_path_node(path, node)) + .collect::>>()?; + + let entries = Box::new(entries); + let length = entries.len(); + + Ok(Tree { + entries: entries.as_ptr(), + entries_ptr: Box::into_raw(entries), + length, + hash: Vec::new().into(), + }) + } + } + } +} + +impl Drop for Tree { + fn drop(&mut self) { + let entry = unsafe { Box::from_raw(self.entries_ptr) }; + drop(entry); + } +}