|
@@ -24,8 +24,8 @@ mod private {
|
|
|
};
|
|
|
|
|
|
use crate::{
|
|
|
- crypto::Creds, Block, BlockMeta, BlockOpenOptions, BlockPath, BoxInIoErr, DirEntry,
|
|
|
- Directory, Epoch, Error, Result, ToStringInIoErr,
|
|
|
+ crypto::Creds, Block, BlockMeta, BlockOpenOptions, BlockPath, BlockRecord, BoxInIoErr,
|
|
|
+ DirEntry, DirEntryKind, Directory, Epoch, Error, Result, ToStringInIoErr,
|
|
|
};
|
|
|
|
|
|
type Inode = u64;
|
|
@@ -70,6 +70,13 @@ mod private {
|
|
|
}
|
|
|
Err(Error::custom(format!("unknown file type: 0o{value:0o}")))
|
|
|
}
|
|
|
+
|
|
|
+ fn dir_entry_kind(self) -> DirEntryKind {
|
|
|
+ match self {
|
|
|
+ Self::Dir => DirEntryKind::Directory,
|
|
|
+ Self::Reg => DirEntryKind::File,
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
impl From<FileType> for libc::mode_t {
|
|
@@ -85,6 +92,12 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ impl From<FileType> for DirEntryKind {
|
|
|
+ fn from(value: FileType) -> Self {
|
|
|
+ value.dir_entry_kind()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
trait SeekFromExt {
|
|
|
/// Converts a C-style `(whence, offset)` pair into a [SeekFrom] enum value.
|
|
|
/// See the POSIX man page of `lseek` for more details.
|
|
@@ -318,7 +331,7 @@ mod private {
|
|
|
self.value(handle)?.access_block_mut(cb)
|
|
|
}
|
|
|
|
|
|
- fn try_borrow_block<T, F: FnOnce(&mut Box<dyn Block>) -> io::Result<T>>(
|
|
|
+ fn borrow_block<T, F: FnOnce(&mut Box<dyn Block>) -> io::Result<T>>(
|
|
|
&mut self,
|
|
|
cb: F,
|
|
|
) -> io::Result<T> {
|
|
@@ -816,19 +829,11 @@ mod private {
|
|
|
.entries
|
|
|
.get(name)
|
|
|
.ok_or_else(|| io::Error::from_raw_os_error(libc::ENOENT))?;
|
|
|
- let inode = match entry {
|
|
|
- DirEntry::File(entry) => entry.inode,
|
|
|
- DirEntry::Directory(entry) => entry.inode,
|
|
|
- DirEntry::Server(_) => {
|
|
|
- return Err(io::Error::new(
|
|
|
- io::ErrorKind::Unsupported,
|
|
|
- "can't lookup server entry",
|
|
|
- ))
|
|
|
- }
|
|
|
- };
|
|
|
+ let inode = entry.inode().ok_or_else(|| {
|
|
|
+ io::Error::new(io::ErrorKind::Unsupported, "can't lookup server entry")
|
|
|
+ })?;
|
|
|
let stat = self.open_value(inode, block_path, |value| {
|
|
|
- let stat =
|
|
|
- value.try_borrow_block(|block| Ok(block.meta_body().secrets()?.stat()))?;
|
|
|
+ let stat = value.borrow_block(|block| Ok(block.meta_body().secrets()?.stat()))?;
|
|
|
value.incr_lookup_count();
|
|
|
Ok(stat)
|
|
|
})?;
|
|
@@ -901,7 +906,7 @@ mod private {
|
|
|
) -> io::Result<(Option<Self::Handle>, OpenOptions)> {
|
|
|
debug!("Blocktree::opendir called on inode {inode}");
|
|
|
let handle = self.access_value_mut(inode, |value| {
|
|
|
- value.try_borrow_block(|block| {
|
|
|
+ value.borrow_block(|block| {
|
|
|
let ctx = AuthzContext::new(ctx, block.meta());
|
|
|
self.authorizer.can_exec(&ctx)?;
|
|
|
Ok(())
|
|
@@ -1192,15 +1197,16 @@ mod private {
|
|
|
|
|
|
block.seek(SeekFrom::Start(0))?;
|
|
|
let mut dir: Directory = read_from(block)?;
|
|
|
- let inode = match dir.entries.remove(name) {
|
|
|
+ let entry = match dir.entries.remove(name) {
|
|
|
None => return Err(io::Error::from_raw_os_error(libc::ENOENT)),
|
|
|
- Some(entry) => entry.inode().ok_or_else(|| {
|
|
|
- io::Error::new(
|
|
|
- io::ErrorKind::InvalidInput,
|
|
|
- format!("name {name} does not refer to a file or directory"),
|
|
|
- )
|
|
|
- })?,
|
|
|
+ Some(entry) => entry,
|
|
|
};
|
|
|
+ let inode = entry.inode().ok_or_else(|| {
|
|
|
+ io::Error::new(
|
|
|
+ io::ErrorKind::Other,
|
|
|
+ "no inode associated with the given name",
|
|
|
+ )
|
|
|
+ })?;
|
|
|
block.seek(SeekFrom::Start(0))?;
|
|
|
write_to(&dir, block)?;
|
|
|
|
|
@@ -1210,7 +1216,7 @@ mod private {
|
|
|
})?;
|
|
|
self.open_value(inode, block_path, |value| {
|
|
|
// We mark the block for deletion if `nlink` drops to zero.
|
|
|
- value.delete = value.try_borrow_block(|block| {
|
|
|
+ value.delete = value.borrow_block(|block| {
|
|
|
let nlink = block.mut_meta_body().access_secrets(|secrets| {
|
|
|
secrets.nlink -= 1;
|
|
|
Ok(secrets.nlink)
|
|
@@ -1222,6 +1228,57 @@ mod private {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ fn link(
|
|
|
+ &self,
|
|
|
+ ctx: &Context,
|
|
|
+ inode: Self::Inode,
|
|
|
+ newparent: Self::Inode,
|
|
|
+ newname: &CStr,
|
|
|
+ ) -> io::Result<Entry> {
|
|
|
+ debug!("Blocktree::link called for inode {inode}");
|
|
|
+ let newname = newname.to_str().box_err()?;
|
|
|
+ self.borrow_block(newparent, |block| {
|
|
|
+ let ctx = AuthzContext::new(ctx, block.meta());
|
|
|
+ self.authorizer.can_write(&ctx)?;
|
|
|
+
|
|
|
+ block.seek(SeekFrom::Start(0))?;
|
|
|
+ let mut dir: Directory = read_from(block)?;
|
|
|
+ if dir.entries.contains_key(newname) {
|
|
|
+ return Err(io::Error::from_raw_os_error(libc::EEXIST));
|
|
|
+ }
|
|
|
+
|
|
|
+ let (file_type, attr) = self.access_value_mut(inode, |value| {
|
|
|
+ let (file_type, attr) = value.borrow_block(|block| {
|
|
|
+ let meta = block.mut_meta_body();
|
|
|
+ let (mode, attr) = meta.access_secrets(|secrets| {
|
|
|
+ secrets.nlink += 1;
|
|
|
+ Ok((secrets.mode, secrets.attr()))
|
|
|
+ })?;
|
|
|
+ let file_type = FileType::from_value(mode)?;
|
|
|
+ block.flush_meta()?;
|
|
|
+ Ok((file_type, attr))
|
|
|
+ })?;
|
|
|
+ value.incr_lookup_count();
|
|
|
+ Ok((file_type, attr))
|
|
|
+ })?;
|
|
|
+ let entry = match file_type {
|
|
|
+ FileType::Reg => DirEntry::File(BlockRecord::new(inode)),
|
|
|
+ FileType::Dir => DirEntry::Directory(BlockRecord::new(inode)),
|
|
|
+ };
|
|
|
+ dir.entries.insert(newname.to_owned(), entry);
|
|
|
+ block.seek(SeekFrom::Start(0))?;
|
|
|
+ write_to(&dir, block)?;
|
|
|
+ Ok(Entry {
|
|
|
+ inode,
|
|
|
+ generation: self.generation,
|
|
|
+ attr: attr.into(),
|
|
|
+ attr_flags: 0,
|
|
|
+ attr_timeout: self.attr_timeout(),
|
|
|
+ entry_timeout: self.entry_timeout(),
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
//////////////////////////////////
|
|
|
// METHODS WHICH ARE NOT SUPPORTED
|
|
|
//////////////////////////////////
|
|
@@ -1320,17 +1377,6 @@ mod private {
|
|
|
Self::not_supported()
|
|
|
}
|
|
|
|
|
|
- fn link(
|
|
|
- &self,
|
|
|
- _ctx: &Context,
|
|
|
- inode: Self::Inode,
|
|
|
- _newparent: Self::Inode,
|
|
|
- _newname: &CStr,
|
|
|
- ) -> io::Result<Entry> {
|
|
|
- debug!("Blocktree::link called for inode {inode}");
|
|
|
- Self::not_supported()
|
|
|
- }
|
|
|
-
|
|
|
fn listxattr(
|
|
|
&self,
|
|
|
_ctx: &Context,
|