diff --git a/Cargo.toml b/Cargo.toml index 15aebf65..b1a3acce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ version = "0.2.0" edition = "2021" license = "Apache-2.0" authors = ["Radu Marias "] +homepage = "https://github.com/radumarias/rencfs" repository = "https://github.com/radumarias/rencfs" readme = "README.md" keywords = ["filesystem", "fuse", "encryption", "system", "security"] diff --git a/examples/arc_hashmap.rs b/examples/arc_hashmap.rs new file mode 100644 index 00000000..77c7592f --- /dev/null +++ b/examples/arc_hashmap.rs @@ -0,0 +1,14 @@ +use rencfs::arc_hashmap::ArcHashMap; + +fn main() { + let mut m = ArcHashMap::new(); + { + let v = m.insert(1, 2); + println!("size {}", m.len()); + m.insert(2, 3); + println!("size {}", m.len()); + let v = m.get_or_insert_with(3, || 4); + println!("size {}", m.len()); + } + println!("size {}", m.len()); +} \ No newline at end of file diff --git a/src/arc_hashmap.rs b/src/arc_hashmap.rs index 6b285761..c438791b 100644 --- a/src/arc_hashmap.rs +++ b/src/arc_hashmap.rs @@ -1,14 +1,14 @@ use std::collections::HashMap; use std::hash::Hash; use std::ops::Deref; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicUsize, Ordering}; pub struct ArcHashMap where - K: Eq + Hash + Copy, + K: Eq + Hash, { - map: HashMap, Arc)>, + map: Mutex, Arc)>>, } pub struct Guard @@ -32,51 +32,50 @@ impl Deref for Guard { } } -impl ArcHashMap { +impl ArcHashMap { pub fn new() -> Self { ArcHashMap { - map: HashMap::new(), + map: Mutex::new(HashMap::new()), } } - pub fn insert(&mut self, key: K, value: V) -> Guard { + pub fn insert(&self, key: K, value: V) -> Guard { self.purge(); self.get_or_insert_with(key, || value) } - pub fn get<'a>(&mut self, key: &K) -> Option> { - let v = self.map.get_mut(key); + pub fn get<'a>(&self, key: &K) -> Option> { + self.purge(); + self.get_internal(self.map.lock().unwrap().get(key)) + } + + pub fn get_internal<'a>(&self, v: Option<&(Arc, Arc)>) -> Option> { if let Some((v, rc)) = v { rc.fetch_add(1, Ordering::SeqCst); return Some(Guard { val: v.clone(), rc: rc.clone() }); } - self.purge(); None } - pub fn get_or_insert_with(&mut self, key: K, f: F) -> Guard + pub fn get_or_insert_with(&self, key: K, f: F) -> Guard where F: FnOnce() -> V, { self.purge(); - let key2 = key.clone(); - self.map.entry(key).or_insert_with(|| { - (Arc::new(f()), Arc::new(AtomicUsize::new(1))) + let mut map = self.map.lock().unwrap(); + let v = map.entry(key).or_insert_with(|| { + (Arc::new(f()), Arc::new(AtomicUsize::new(0))) }); - self.get(&key2).unwrap() + self.get_internal(Some(v)).unwrap() } - fn purge(&mut self) { - let keys = self.map.keys().cloned().collect::>(); - for k in keys { - if self.map.get(&k).unwrap().1.load(Ordering::SeqCst) == 0 { - self.map.remove(&k); - } - } + fn purge(&self) { + let mut map = self.map.lock().unwrap(); + map.retain(|_, v| v.1.load(Ordering::SeqCst) > 0); } - pub fn len(&mut self) -> usize { + pub fn len(&self) -> usize { self.purge(); - self.map.len() + self.map.lock().unwrap().len() } } \ No newline at end of file diff --git a/src/encryptedfs.rs b/src/encryptedfs.rs index 64dda666..a55bae3f 100644 --- a/src/encryptedfs.rs +++ b/src/encryptedfs.rs @@ -5,9 +5,9 @@ use std::fmt::Debug; use std::fs::{File, OpenOptions, ReadDir}; use std::io::{Read, Write}; use std::ops::Deref; -use std::os::unix::fs::MetadataExt; use std::path::PathBuf; use std::str::FromStr; +use std::sync::Arc; use std::sync::atomic::AtomicU64; use std::time::{Duration, SystemTime}; @@ -363,7 +363,7 @@ impl PartialEq for DirectoryEntryPlus { pub type FsResult = Result; -pub struct DirectoryEntryIterator(ReadDir, Cipher, SecretVec); +pub struct DirectoryEntryIterator(ReadDir, Cipher, Arc>, Arc>>>); impl Iterator for DirectoryEntryIterator { type Item = FsResult; @@ -374,10 +374,16 @@ impl Iterator for DirectoryEntryIterator { return Some(Err(e.into())); } let entry = entry.unwrap(); + + let map = self.3.read().unwrap(); + let lock = map.get_or_insert_with(entry.path().to_str().unwrap().to_string(), || std::sync::RwLock::new(false)); + let _guard = lock.read().unwrap(); + let file = File::open(entry.path()); if let Err(e) = file { return Some(Err(e.into())); } + let file = file.unwrap(); let name = entry.file_name().to_string_lossy().to_string(); let name = { @@ -389,6 +395,7 @@ impl Iterator for DirectoryEntryIterator { crypto_util::decrypt_and_unnormalize_end_file_name(&name, &self.1, &self.2) } }; + let res: bincode::Result<(u64, FileType)> = bincode::deserialize_from(crypto_util::create_decryptor(file, &self.1, &self.2)); if let Err(e) = res { return Some(Err(e.into())); @@ -398,7 +405,9 @@ impl Iterator for DirectoryEntryIterator { } } -pub struct DirectoryEntryPlusIterator(ReadDir, PathBuf, Cipher, SecretVec); +pub struct DirectoryEntryPlusIterator(ReadDir, PathBuf, Cipher, Arc>, + Arc>>>, + Arc>>>); impl Iterator for DirectoryEntryPlusIterator { type Item = FsResult; @@ -411,6 +420,11 @@ impl Iterator for DirectoryEntryPlusIterator { return Some(Err(e.into())); } let entry = entry.unwrap(); + + let map = self.4.read().unwrap(); + let lock = map.get_or_insert_with(entry.path().to_str().unwrap().to_string(), || std::sync::RwLock::new(false)); + let _guard = lock.read().unwrap(); + let file = File::open(entry.path()); if let Err(e) = file { error!(err = %e, "opening file"); @@ -434,6 +448,10 @@ impl Iterator for DirectoryEntryPlusIterator { } let (ino, kind): (u64, FileType) = res.unwrap(); + let map_guard_ino = self.5.read().unwrap(); + let lock_ino = map_guard_ino.get_or_insert_with(ino, || std::sync::RwLock::new(false)); + let _guard_ino = lock_ino.read().unwrap(); + let file = File::open(&self.1.join(ino.to_string())); if let Err(e) = file { error!(err = %e, "opening file"); @@ -562,9 +580,10 @@ pub struct EncryptedFs { opened_files_for_read: RwLock>>, opened_files_for_write: RwLock>, // used for rw ops of actual serialization - serialize_inode_locks: Mutex>>, + serialize_inode_locks: Arc>>>, // used for the update op serialize_update_inode_locks: Mutex>>, + serialize_dir_entries_locks: Arc>>>, read_write_inode_locks: Mutex>>, key: ExpireValue, FsError, KeyProvider>, } @@ -580,6 +599,7 @@ impl EncryptedFs { let path = PathBuf::from(&data_dir); ensure_structure_created(&path.clone()).await?; + check_password(&path, &password, &cipher)?; let key_provider = KeyProvider { path: path.join(SECURITY_DIR).join(KEY_ENC_FILENAME), @@ -597,11 +617,13 @@ impl EncryptedFs { opened_files_for_read: RwLock::new(HashMap::new()), opened_files_for_write: RwLock::new(HashMap::new()), read_write_inode_locks: Mutex::new(ArcHashMap::new()), - serialize_inode_locks: Mutex::new(ArcHashMap::new()), + serialize_inode_locks: Arc::new(std::sync::RwLock::new(ArcHashMap::new())), serialize_update_inode_locks: Mutex::new(ArcHashMap::new()), + serialize_dir_entries_locks: Arc::new(std::sync::RwLock::new(ArcHashMap::new())), // todo: take duration from param key: ExpireValue::new(key_provider, Duration::from_secs(10 * 60)).await, }; + let _ = fs.ensure_root_exists().await; Ok(fs) @@ -638,7 +660,7 @@ impl EncryptedFs { attr.ino = self.generate_next_inode(); // write inode - self.write_inode(&attr).await?; + self.write_inode_to_storage(&attr, &*self.key.get().await?).await?; // create in contents directory match attr.kind { @@ -660,12 +682,12 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::from_str("$.").unwrap(), kind: FileType::Directory, - }).await?; + }, &*self.key.get().await?).await?; self.insert_directory_entry(attr.ino, DirectoryEntry { ino: parent, name: SecretString::from_str("$..").unwrap(), kind: FileType::Directory, - }).await?; + }, &*self.key.get().await?).await?; } } @@ -674,11 +696,10 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::new(name.expose_secret().to_owned()), kind: attr.kind, - }).await?; - let mut parent_attr = self.get_inode(parent).await?; - parent_attr.mtime = SystemTime::now(); - parent_attr.ctime = SystemTime::now(); - self.write_inode(&parent_attr).await?; + }, &*self.key.get().await?).await?; + self.update_inode(parent, SetFileAttr::default() + .with_mtime(SystemTime::now()) + .with_ctime(SystemTime::now())).await?; let handle = if attr.kind == FileType::RegularFile { if read || write { @@ -747,18 +768,23 @@ impl EncryptedFs { } let ino_str = attr.ino.to_string(); + // remove inode file - tokio::fs::remove_file(self.data_dir.join(INODES_DIR).join(&ino_str)).await?; + { + let map = self.serialize_inode_locks.write().unwrap(); + let lock = map.get_or_insert_with(attr.ino, || std::sync::RwLock::new(false)); + let _guard = lock.write().unwrap(); + fs::remove_file(self.data_dir.join(INODES_DIR).join(&ino_str))?; + } + // remove contents directory tokio::fs::remove_dir_all(self.data_dir.join(CONTENTS_DIR).join(&ino_str)).await?; // remove from parent directory - let name = crypto_util::normalize_end_encrypt_file_name(name, &self.cipher, &*self.key.get().await?); - tokio::fs::remove_file(self.data_dir.join(CONTENTS_DIR).join(parent.to_string()).join(name)).await?; + self.remove_directory_entry(parent, name).await?; - let mut parent_attr = self.get_inode(parent).await?; - parent_attr.mtime = SystemTime::now(); - parent_attr.ctime = SystemTime::now(); - self.write_inode(&parent_attr).await?; + self.update_inode(parent, SetFileAttr::default() + .with_mtime(SystemTime::now()) + .with_ctime(SystemTime::now())).await?; Ok(()) } @@ -778,17 +804,22 @@ impl EncryptedFs { let ino_str = attr.ino.to_string(); // remove inode file - tokio::fs::remove_file(self.data_dir.join(INODES_DIR).join(&ino_str)).await?; + { + let map = self.serialize_inode_locks.write().unwrap(); + let lock = map.get_or_insert_with(attr.ino, || std::sync::RwLock::new(false)); + let _guard = lock.write().unwrap(); + fs::remove_file(self.data_dir.join(INODES_DIR).join(&ino_str))?; + } + // remove contents file tokio::fs::remove_file(self.data_dir.join(CONTENTS_DIR).join(&ino_str)).await?; // remove from parent directory - let name = crypto_util::normalize_end_encrypt_file_name(name, &self.cipher, &*self.key.get().await?); - tokio::fs::remove_file(self.data_dir.join(CONTENTS_DIR).join(parent.to_string()).join(name)).await?; + // remove from parent contents + self.remove_directory_entry(parent, name).await?; - let mut parent_attr = self.get_inode(parent).await?; - parent_attr.mtime = SystemTime::now(); - parent_attr.ctime = SystemTime::now(); - self.write_inode(&parent_attr).await?; + self.update_inode(parent, SetFileAttr::default() + .with_mtime(SystemTime::now()) + .with_ctime(SystemTime::now())).await?; Ok(()) } @@ -814,7 +845,7 @@ impl EncryptedFs { } let iter = fs::read_dir(contents_dir)?; - Ok(DirectoryEntryIterator(iter.into_iter(), self.cipher.clone(), SecretVec::new((*self.key.get().await?).expose_secret().to_vec()))) + Ok(DirectoryEntryIterator(iter.into_iter(), self.cipher.clone(), self.key.get().await?, self.serialize_dir_entries_locks.clone())) } /// Like [read_dir](EncryptedFs::read_dir) but with [FileAttr] so we don't need to query again for those. @@ -825,22 +856,23 @@ impl EncryptedFs { } let iter = fs::read_dir(contents_dir)?; - Ok(DirectoryEntryPlusIterator(iter.into_iter(), self.data_dir.join(INODES_DIR), self.cipher.clone(), SecretVec::new((*self.key.get().await?).expose_secret().to_vec()))) + Ok(DirectoryEntryPlusIterator(iter.into_iter(), self.data_dir.join(INODES_DIR), self.cipher.clone(), self.key.get().await?, + self.serialize_dir_entries_locks.clone(), self.serialize_inode_locks.clone())) } - async fn get_inode_from_storage(&self, ino: u64) -> FsResult { - let mut map_guard = self.serialize_inode_locks.lock().await; - let lock = map_guard.get_or_insert_with(ino, || Mutex::new(false)); - let _guard = lock.lock().await; + async fn get_inode_from_storage(&self, ino: u64, key: &SecretVec) -> FsResult { + let map_guard = self.serialize_inode_locks.read().unwrap(); + let lock = map_guard.get_or_insert_with(ino, || std::sync::RwLock::new(false)); + let _guard = lock.read().unwrap(); let path = self.data_dir.join(INODES_DIR).join(ino.to_string()); let file = OpenOptions::new().read(true).write(true).open(path).map_err(|_| { FsError::InodeNotFound })?; - Ok(bincode::deserialize_from::, FileAttr>(crypto_util::create_decryptor(file, &self.cipher, &*self.key.get().await?))?) + Ok(bincode::deserialize_from::, FileAttr>(crypto_util::create_decryptor(file, &self.cipher, key))?) } pub async fn get_inode(&self, ino: u64) -> FsResult { debug!("get inode"); - let mut attr = self.get_inode_from_storage(ino).await?; + let mut attr = self.get_inode_from_storage(ino, &*self.key.get().await?).await?; // merge time info and size with any open read handles let open_reads = { self.opened_files_for_read.read().await.contains_key(&ino) }; @@ -872,21 +904,21 @@ impl EncryptedFs { } pub async fn update_inode(&self, ino: u64, set_attr: SetFileAttr) -> FsResult<()> { - let mut map_serialize_update = self.serialize_update_inode_locks.lock().await; + let map_serialize_update = self.serialize_update_inode_locks.lock().await; let lock_serialize_update = map_serialize_update.get_or_insert_with(ino, || Mutex::new(false)); let _guard_serialize_update = lock_serialize_update.lock().await; let mut attr = self.get_inode(ino).await?; merge_attr(&mut attr, set_attr); - self.write_inode(&attr).await?; + self.write_inode_to_storage(&attr, &*self.key.get().await?).await?; Ok(()) } - async fn write_inode(&self, attr: &FileAttr) -> Result<(), FsError> { - let mut map = self.serialize_inode_locks.lock().await; - let lock = map.get_or_insert_with(attr.ino, || Mutex::new(false)); - let _guard = lock.lock().await; + async fn write_inode_to_storage(&self, attr: &FileAttr, key: &SecretVec) -> Result<(), FsError> { + let map = self.serialize_inode_locks.write().unwrap(); + let lock = map.get_or_insert_with(attr.ino, || std::sync::RwLock::new(false)); + let _guard = lock.write().unwrap(); let path = self.data_dir.join(INODES_DIR).join(attr.ino.to_string()); let file = OpenOptions::new() @@ -895,7 +927,7 @@ impl EncryptedFs { .create(true) .truncate(true) .open(&path)?; - bincode::serialize_into(crypto_util::create_encryptor(file, &self.cipher, &*self.key.get().await?), &attr)?; + bincode::serialize_into(crypto_util::create_encryptor(file, &self.cipher, key), &attr)?; Ok(()) } @@ -910,7 +942,7 @@ impl EncryptedFs { debug!("read"); // lock for reading let lock = { - let mut map_guard = self.read_write_inode_locks.lock().await; + let map_guard = self.read_write_inode_locks.lock().await; map_guard.get_or_insert_with(ino, || Mutex::new(false)) }; let _guard = lock.lock().await; @@ -1056,9 +1088,9 @@ impl EncryptedFs { if !valid_fh { return Err(FsError::InvalidFileHandle); } - debug!(serialize_inode_locks.size = self.serialize_inode_locks.lock().await.len()); - debug!(read_write_inode_locks.size = self.read_write_inode_locks.lock().await.len()); + debug!(serialize_inode_locks.size = self.serialize_inode_locks.read().unwrap().len()); debug!(serialize_update_inode_locks.size = self.serialize_update_inode_locks.lock().await.len()); + debug!(read_write_inode_locks.size = self.read_write_inode_locks.lock().await.len()); Ok(()) } @@ -1084,7 +1116,7 @@ impl EncryptedFs { debug!("write_all"); // lock for writing let lock = { - let mut map_guard = self.read_write_inode_locks.lock().await; + let map_guard = self.read_write_inode_locks.lock().await; map_guard.get_or_insert_with(ino, || Mutex::new(false)) }; let _guard = lock.lock().await; @@ -1168,7 +1200,7 @@ impl EncryptedFs { // update metadata let (ino, attr) = { let guard = self.write_handles.read().await; - let mut ctx = guard.get(&handle).unwrap().lock().await; + let ctx = guard.get(&handle).unwrap().lock().await; (ctx.ino, ctx.attr.clone()) }; self.update_inode(ino, attr.into()).await?; @@ -1326,7 +1358,7 @@ impl EncryptedFs { return Err(FsError::InvalidInodeType); } - let mut map_guard = self.read_write_inode_locks.lock().await; + let map_guard = self.read_write_inode_locks.lock().await; let mut handle = 0_u64; if read { let lock = map_guard.get_or_insert_with(ino, || Mutex::new(false)); @@ -1350,7 +1382,7 @@ impl EncryptedFs { pub async fn truncate(&self, ino: u64, size: u64) -> FsResult<()> { let lock = { - let mut map_guard = self.read_write_inode_locks.lock().await; + let map_guard = self.read_write_inode_locks.lock().await; map_guard.get_or_insert_with(ino, || Mutex::new(false)) }; let _guard = lock.lock().await; @@ -1556,7 +1588,7 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::new(new_name.expose_secret().to_owned()), kind: attr.kind, - }).await?; + }, &*self.key.get().await?).await?; let mut parent_attr = self.get_inode(parent).await?; parent_attr.mtime = SystemTime::now(); @@ -1574,7 +1606,7 @@ impl EncryptedFs { ino: new_parent, name: SecretString::from_str("$..").unwrap(), kind: FileType::Directory, - }).await?; + }, &*self.key.get().await?).await?; } Ok(()) @@ -1682,7 +1714,7 @@ impl EncryptedFs { let path = self.data_dir.join(CONTENTS_DIR).join(ino.to_string()); let file = OpenOptions::new().read(true).write(true).open(path)?; let decryptor = crypto_util::create_decryptor(file, &self.cipher, &*self.key.get().await?); - let attr = self.get_inode_from_storage(ino).await?; + let attr = self.get_inode_from_storage(ino, &*self.key.get().await?).await?; match op { ReadHandleContextOperation::Create { ino, lock } => { let attr: TimeAndSizeFileAttr = attr.into(); @@ -1734,7 +1766,7 @@ impl EncryptedFs { existing.encryptor.replace(encryptor); existing.path = path.clone(); if reset_size { - let attr = self.get_inode_from_storage(ino).await?; + let attr = self.get_inode_from_storage(ino, &*self.key.get().await?).await?; existing.attr.size = attr.size; debug!("resetting size to {}", attr.size.to_formatted_string(&Locale::en)); } @@ -1746,30 +1778,21 @@ impl EncryptedFs { async fn ensure_root_exists(&self) -> FsResult<()> { if !self.node_exists(ROOT_INODE) { - let mut attr = FileAttr { - ino: ROOT_INODE, - size: 0, - blocks: 0, - atime: SystemTime::now(), - mtime: SystemTime::now(), - ctime: SystemTime::now(), - crtime: SystemTime::now(), + let mut attr: FileAttr = CreateFileAttr { kind: FileType::Directory, perm: 0o755, - nlink: 2, uid: 0, gid: 0, rdev: 0, - blksize: 0, flags: 0, - }; - #[cfg(target_os = "linux")] { - let metadata = tokio::fs::metadata(self.data_dir.clone()).await?; - attr.uid = metadata.uid(); - attr.gid = metadata.gid(); + }.into(); + attr.ino = ROOT_INODE; + #[cfg(target_os = "linux")] unsafe { + attr.uid = libc::getuid(); + attr.gid = libc::getgid(); } - self.write_inode(&attr).await?; + self.write_inode_to_storage(&attr, &*self.key.get().await?).await?; // create the directory tokio::fs::create_dir(self.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string())).await?; @@ -1779,25 +1802,30 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::from_str("$.").unwrap(), kind: FileType::Directory, - }).await?; + }, &*self.key.get().await?).await?; } Ok(()) } - async fn insert_directory_entry(&self, parent: u64, entry: DirectoryEntry) -> FsResult<()> { + async fn insert_directory_entry(&self, parent: u64, entry: DirectoryEntry, key: &SecretVec) -> FsResult<()> { let parent_path = self.data_dir.join(CONTENTS_DIR).join(parent.to_string()); - // remove path separators from name let name = crypto_util::normalize_end_encrypt_file_name(&entry.name, &self.cipher, &*self.key.get().await?); + let file_path = parent_path.join(name); + + let map = self.serialize_dir_entries_locks.write().unwrap(); + let lock = map.get_or_insert_with(file_path.to_str().unwrap().to_string(), || std::sync::RwLock::new(false)); + let _guard = lock.write().unwrap(); + let file = OpenOptions::new() .write(true) .create(true) .truncate(true) - .open(&parent_path.join(name))?; + .open(&file_path)?; // write inode and file type let entry = (entry.ino, entry.kind); - bincode::serialize_into(crypto_util::create_encryptor(file, &self.cipher, &*self.key.get().await?), &entry)?; + bincode::serialize_into(crypto_util::create_encryptor(file, &self.cipher, key), &entry)?; Ok(()) } @@ -1805,7 +1833,13 @@ impl EncryptedFs { async fn remove_directory_entry(&self, parent: u64, name: &SecretString) -> FsResult<()> { let parent_path = self.data_dir.join(CONTENTS_DIR).join(parent.to_string()); let name = crypto_util::normalize_end_encrypt_file_name(name, &self.cipher, &*self.key.get().await?); - tokio::fs::remove_file(parent_path.join(name)).await?; + let file_path = parent_path.join(name); + + let map = self.serialize_dir_entries_locks.write().unwrap(); + let lock = map.get_or_insert_with(file_path.to_str().unwrap().to_string(), || std::sync::RwLock::new(false)); + let _guard = lock.write().unwrap(); + + fs::remove_file(file_path)?; Ok(()) } @@ -1930,3 +1964,17 @@ fn merge_attr(attr: &mut FileAttr, set_attr: SetFileAttr) { attr.flags = flags; } } + +fn check_password(data_dir: &PathBuf, password: &SecretString, cipher: &Cipher) -> FsResult<()> { + let salt = crypto_util::hash_secret(password); + let initial_key = crypto_util::derive_key(password, cipher, salt)?; + let enc_file = data_dir.join(SECURITY_DIR).join(KEY_ENC_FILENAME); + let decryptor = crypto_util::create_decryptor(File::open(enc_file.clone())?, cipher, &initial_key); + let key_store: KeyStore = bincode::deserialize_from(decryptor).map_err(|_| FsError::InvalidPassword)?; + // check hash + if key_store.hash != crypto_util::hash(key_store.key.expose_secret()) { + return Err(FsError::InvalidPassword); + } + + Ok(()) +} diff --git a/src/encryptedfs_fuse3.rs b/src/encryptedfs_fuse3.rs index 1a87c8b2..c71c9561 100644 --- a/src/encryptedfs_fuse3.rs +++ b/src/encryptedfs_fuse3.rs @@ -15,7 +15,7 @@ use fuse3::raw::prelude::{DirectoryEntry, DirectoryEntryPlus, ReplyAttr, ReplyCo use fuse3::raw::{Filesystem, Request}; use futures_util::stream; use futures_util::stream::Iter; -use libc::{EACCES, EBADF, EIO, ENOENT, ENOTDIR, ENOTEMPTY, EPERM}; +use libc::{EACCES, EBADF, EEXIST, EIO, ENAMETOOLONG, ENOENT, ENOTDIR, ENOTEMPTY, EPERM}; use secrecy::{ExposeSecret, SecretString}; use tracing::{debug, error, instrument, trace, warn}; @@ -185,16 +185,15 @@ impl EncryptedFsFuse3 { attr.uid = req.uid; attr.gid = creation_gid(&parent_attr, req.gid); - match self.get_fs().create_nod(parent, &SecretString::from_str(name.to_str().unwrap()).unwrap(), attr, read, write).await { - Ok((fh, attr)) => Ok((fh, attr)), - Err(err) => { - error!(err = %err); - match err { - FsError::AlreadyExists => { Err(libc::EEXIST) } - _ => { return Err(ENOENT); } - } + let (fh, attr) = self.get_fs().create_nod(parent, &SecretString::from_str(name.to_str().unwrap()).unwrap(), attr, read, write).await.map_err(|err| { + error!(err = %err); + match err { + FsError::AlreadyExists => EEXIST, + FsError::Io { source } => if source.to_string().to_lowercase().contains("too long") { ENAMETOOLONG } else { EIO }, + _ => EIO, } - } + })?; + Ok((fh, attr)) } } @@ -251,7 +250,7 @@ impl Filesystem for EncryptedFsFuse3 { if name.len() > MAX_NAME_LENGTH as usize { warn!(name = %name.to_str().unwrap(), "name too long"); - return Err(libc::ENAMETOOLONG.into()); + return Err(ENAMETOOLONG.into()); } match self.get_fs().get_inode(parent).await { @@ -1068,26 +1067,20 @@ impl Filesystem for EncryptedFsFuse3 { } }; - return match self.create_nod(parent, mode, &req, name, read, write).await { - Ok((handle, attr)) => { - debug!(handle, "created handle"); - // TODO: implement flags - Ok(ReplyCreated { - ttl: TTL, - attr: attr.into(), - generation: 0, - fh: handle, - flags: 0, - }) - } - Err(err) => { - error!(err = %err); - Err(ENOENT.into()) - } - }; + let (handle, attr) = self.create_nod(parent, mode, &req, name, read, write).await.map_err(|err| { + error!(err = %err); + Errno::from(ENOENT) + })?; + debug!(handle, "created handle"); + Ok(ReplyCreated { + ttl: TTL, + attr: attr.into(), + generation: 0, + fh: handle, + flags: 0, + }) } - type DirEntryPlusStream<'a> = Iter> where Self: 'a; #[instrument(skip(self), err(level = Level::INFO))]