From 479f0913311ce5d853acdbabb21ce4a3edee915c Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 16:56:00 -0500 Subject: [PATCH 1/8] Revised Init unit test. Fixed a bug where the unit test for `Init` in `ll::request` would fail for certain abi versions (e.g., `abi-7-36`). --- src/ll/request.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/ll/request.rs b/src/ll/request.rs index b560a29f..3808ef0d 100644 --- a/src/ll/request.rs +++ b/src/ll/request.rs @@ -2175,8 +2175,9 @@ mod tests { use super::*; use std::ffi::OsStr; - #[cfg(target_endian = "big")] + #[cfg(all(target_endian = "big", not(feature = "abi-7-36")))] const INIT_REQUEST: AlignedData<[u8; 56]> = AlignedData([ + // decimal 56 == hex 0x38 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1a, // len, opcode 0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xd0, 0x0d, // unique 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // nodeid @@ -2186,8 +2187,9 @@ mod tests { 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // max_readahead, flags ]); - #[cfg(target_endian = "little")] + #[cfg(all(target_endian = "little", not(feature = "abi-7-36")))] const INIT_REQUEST: AlignedData<[u8; 56]> = AlignedData([ + // decimal 56 == hex 0x38 0x38, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, // len, opcode 0x0d, 0xf0, 0xad, 0xba, 0xef, 0xbe, 0xad, 0xde, // unique 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // nodeid @@ -2197,6 +2199,40 @@ mod tests { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // max_readahead, flags ]); + #[cfg(all(target_endian = "big", feature = "abi-7-36"))] + const INIT_REQUEST: AlignedData<[u8; 104]> = AlignedData([ + // decimal 104 == hex 0x68 + 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x1a, // len, opcode + 0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xd0, 0x0d, // unique + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // nodeid + 0xc0, 0x01, 0xd0, 0x0d, 0xc0, 0x01, 0xca, 0xfe, // uid, gid + 0xc0, 0xde, 0xba, 0x5e, 0x00, 0x00, 0x00, 0x00, // pid, padding + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, // major, minor + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // max_readahead, flags + 0x00, 0x00, 0x00, 0x00, // flags2 //TODO: nonzero data + 0x00, 0x00, 0x00, 0x00, // eleven unused fields + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]); + + #[cfg(all(target_endian = "little", feature = "abi-7-36"))] + const INIT_REQUEST: AlignedData<[u8; 104]> = AlignedData([ + // decimal 104 == hex 0x68 + 0x68, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, // len, opcode + 0x0d, 0xf0, 0xad, 0xba, 0xef, 0xbe, 0xad, 0xde, // unique + 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // nodeid + 0x0d, 0xd0, 0x01, 0xc0, 0xfe, 0xca, 0x01, 0xc0, // uid, gid + 0x5e, 0xba, 0xde, 0xc0, 0x00, 0x00, 0x00, 0x00, // pid, padding + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // major, minor + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // max_readahead, flags + 0x00, 0x00, 0x00, 0x00, // flags2 //TODO: nonzero data + 0x00, 0x00, 0x00, 0x00, // eleven unused fields + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]); + #[cfg(target_endian = "big")] const MKNOD_REQUEST: AlignedData<[u8; 56]> = [ 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, // len, opcode @@ -2231,7 +2267,10 @@ mod tests { #[test] fn short_read() { match AnyRequest::try_from(&INIT_REQUEST[..48]) { + #[cfg(not(feature = "abi-7-36"))] Err(RequestError::ShortRead(48, 56)) => (), + #[cfg(feature = "abi-7-36")] + Err(RequestError::ShortRead(48, 104)) => (), _ => panic!("Unexpected request parsing result"), } } @@ -2239,7 +2278,10 @@ mod tests { #[test] fn init() { let req = AnyRequest::try_from(&INIT_REQUEST[..]).unwrap(); + #[cfg(not(feature = "abi-7-36"))] assert_eq!(req.header.len, 56); + #[cfg(feature = "abi-7-36")] + assert_eq!(req.header.len, 104); assert_eq!(req.header.opcode, 26); assert_eq!(req.unique(), RequestId(0xdead_beef_baad_f00d)); assert_eq!(req.nodeid(), INodeNo(0x1122_3344_5566_7788)); From bd0d7b794ab5cec713252d34481d6b0798af9498 Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 16:58:38 -0500 Subject: [PATCH 2/8] Cross-platform documentation. Fixed a bug where the documentation was missing from the `NO_XATTR` constant on a non-linux OS. Using a macro to prevent duplication. --- src/ll/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ll/mod.rs b/src/ll/mod.rs index 14057640..6545288b 100644 --- a/src/ll/mod.rs +++ b/src/ll/mod.rs @@ -35,6 +35,10 @@ macro_rules! errno { }; } +macro_rules! no_xattr_doc { + () => {"Use this as an error return from getxattr/removexattr to indicate that the xattr doesn't exist. This resolves to the appropriate platform-specific error code."} +} + /// Represents an error code to be returned to the caller #[derive(Debug)] pub struct Errno(pub NonZeroI32); @@ -213,14 +217,14 @@ impl Errno { /// No data available #[cfg(target_os = "linux")] pub const ENODATA: Errno = errno!(libc::ENODATA); + #[doc = no_xattr_doc!()] + #[cfg(target_os = "linux")] + pub const NO_XATTR: Errno = Self::ENODATA; + /// Attribute not found #[cfg(not(target_os = "linux"))] pub const ENOATTR: Errno = errno!(libc::ENOATTR); - - /// Use this as an error return from getxattr/removexattr to indicate that the xattr doesn't - /// exist. This resolves to the appropriate platform specific error code. - #[cfg(target_os = "linux")] - pub const NO_XATTR: Errno = Self::ENODATA; + #[doc = no_xattr_doc!()] #[cfg(not(target_os = "linux"))] pub const NO_XATTR: Errno = Self::ENOATTR; From 0ed062a3e53331d7aeefd66e834eacd71fd0c135 Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 16:59:46 -0500 Subject: [PATCH 3/8] Big literal. Clippy says it's better to write long constants with underscore separators: [https://rust-lang.github.io/rust-clippy/rust-1.51.0/index.html#unreadable_literal] --- examples/passthrough.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/passthrough.rs b/examples/passthrough.rs index 299c0060..bd865c3c 100644 --- a/examples/passthrough.rs +++ b/examples/passthrough.rs @@ -112,7 +112,7 @@ impl PassthroughFs { let passthrough_file_attr = FileAttr { ino: 2, - size: 123456, + size: 123_456, blocks: 1, atime: UNIX_EPOCH, // 1970-01-01 00:00:00 mtime: UNIX_EPOCH, From 43ea52b7ac3187e903f444afe791b16dfa41d5f8 Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 17:03:36 -0500 Subject: [PATCH 4/8] Clarified privacy. Promoted some important items to `public(crate)` for easier testing and future reorganization. --- src/ll/mod.rs | 2 +- src/ll/reply.rs | 11 ++++++----- src/passthrough.rs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ll/mod.rs b/src/ll/mod.rs index 6545288b..624b01c2 100644 --- a/src/ll/mod.rs +++ b/src/ll/mod.rs @@ -4,7 +4,7 @@ mod argument; pub mod fuse_abi; pub(crate) mod notify; pub(crate) mod reply; -mod request; +pub(crate) mod request; use std::{convert::TryInto, num::NonZeroI32, time::SystemTime}; diff --git a/src/ll/reply.rs b/src/ll/reply.rs index c8e95f83..204fa34f 100644 --- a/src/ll/reply.rs +++ b/src/ll/reply.rs @@ -247,7 +247,7 @@ impl<'a> Response<'a> { Self::from_struct(&r) } - fn new_directory(list: EntListBuf) -> Self { + pub(crate) fn new_directory(list: EntListBuf) -> Self { assert!(list.buf.len() <= list.max_size); Self::Data(list.buf) } @@ -262,7 +262,7 @@ impl<'a> Response<'a> { Self::from_struct(&r) } - fn from_struct(data: &T) -> Self { + pub(crate) fn from_struct(data: &T) -> Self { Self::Data(SmallVec::from_slice(data.as_bytes())) } } @@ -349,12 +349,13 @@ impl From for Attr { } #[derive(Debug)] -struct EntListBuf { +/// A generic data buffer +pub(crate) struct EntListBuf { max_size: usize, buf: ResponseBuf, } impl EntListBuf { - fn new(max_size: usize) -> Self { + pub(crate) fn new(max_size: usize) -> Self { Self { max_size, buf: ResponseBuf::new(), @@ -365,7 +366,7 @@ impl EntListBuf { /// A transparent offset value can be provided for each entry. The kernel uses these /// value to request the next entries in further readdir calls #[must_use] - fn push(&mut self, ent: [&[u8]; 2]) -> bool { + pub(crate) fn push(&mut self, ent: [&[u8]; 2]) -> bool { let entlen = ent[0].len() + ent[1].len(); let entsize = (entlen + size_of::() - 1) & !(size_of::() - 1); // 64bit align if self.buf.len() + entsize > self.max_size { diff --git a/src/passthrough.rs b/src/passthrough.rs index 6376d5ff..24b283c0 100644 --- a/src/passthrough.rs +++ b/src/passthrough.rs @@ -45,7 +45,7 @@ nix::ioctl_write_ptr!( /// make that call (if the channel hasn't already been closed). #[derive(Debug)] pub struct BackingId { - channel: Weak, + pub(crate) channel: Weak, /// The `backing_id` field passed to and from the kernel pub(crate) backing_id: u32, } From eede324a74f47bebd4c917d8e1fa83900917375f Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 17:07:25 -0500 Subject: [PATCH 5/8] Universal file target. Fixed a bug where the passthrough test would fail on macOS simply because the target file doesn't exist. It can still fail, but the test failure should be related to the feature being tested (i.e., passthrough). --- examples/passthrough.rs | 2 +- tests/test_passthrough.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/passthrough.rs b/examples/passthrough.rs index bd865c3c..a7277430 100644 --- a/examples/passthrough.rs +++ b/examples/passthrough.rs @@ -172,7 +172,7 @@ impl Filesystem for PassthroughFs { let (fh, id) = self .backing_cache .get_or(ino, || { - let file = File::open("/etc/os-release")?; + let file = File::open("/etc/profile")?; reply.open_backing(file) }) .unwrap(); diff --git a/tests/test_passthrough.sh b/tests/test_passthrough.sh index 0224af33..111be92b 100755 --- a/tests/test_passthrough.sh +++ b/tests/test_passthrough.sh @@ -34,7 +34,7 @@ for x in $(seq 10); do sleep 1 done -expected="$(sha256sum - < /usr/lib/os-release)" +expected="$(sha256sum - < /etc/profile)" # Check that it's equal to the underlying file test "$(sha256sum - < "${mnt}/passthrough")" = "${expected}" From 9bec88b6edf0243a4fa0e551ed433dcbb6a72c03 Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 15:35:02 -0500 Subject: [PATCH 6/8] Cast up, rather than down. It's safer to define the block size as u32 (its true native type) and cast up to u64 as needed for file attr. --- examples/simple.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 0679bfd2..ad0be4f7 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -33,7 +33,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::{env, fs, io}; -const BLOCK_SIZE: u64 = 512; +const BLOCK_SIZE: u32 = 512; const MAX_NAME_LENGTH: u32 = 255; const MAX_FILE_SIZE: u64 = 1024 * 1024 * 1024 * 1024; @@ -221,7 +221,7 @@ impl From for fuser::FileAttr { fuser::FileAttr { ino: attrs.inode, size: attrs.size, - blocks: attrs.size.div_ceil(BLOCK_SIZE), + blocks: attrs.size.div_ceil(u64::from(BLOCK_SIZE)), atime: system_time_from_time(attrs.last_accessed.0, attrs.last_accessed.1), mtime: system_time_from_time(attrs.last_modified.0, attrs.last_modified.1), ctime: system_time_from_time( @@ -235,7 +235,7 @@ impl From for fuser::FileAttr { uid: attrs.uid, gid: attrs.gid, rdev: 0, - blksize: BLOCK_SIZE as u32, + blksize: BLOCK_SIZE, flags: 0, } } @@ -900,7 +900,7 @@ impl Filesystem for SimpleFS { let attrs = InodeAttributes { inode, open_file_handles: 0, - size: BLOCK_SIZE, + size: u64::from(BLOCK_SIZE), last_accessed: time_now(), last_modified: time_now(), last_metadata_changed: time_now(), @@ -1596,9 +1596,9 @@ impl Filesystem for SimpleFS { 10_000, 1, 10_000, - BLOCK_SIZE as u32, + BLOCK_SIZE, MAX_NAME_LENGTH, - BLOCK_SIZE as u32, + BLOCK_SIZE, ); } From eeef4fbd8936a62588234e86031f2c2c0fda385f Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 15:40:31 -0500 Subject: [PATCH 7/8] Remove unused self. These `check_*` helper functions don't borrow anything from self, so they are better expressed as associated functions. --- examples/simple.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index ad0be4f7..6a69595b 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -316,11 +316,11 @@ impl SimpleFS { fh } - fn check_file_handle_read(&self, file_handle: u64) -> bool { + fn check_file_handle_read(file_handle: u64) -> bool { (file_handle & FILE_HANDLE_READ_BIT) != 0 } - fn check_file_handle_write(&self, file_handle: u64) -> bool { + fn check_file_handle_write(file_handle: u64) -> bool { (file_handle & FILE_HANDLE_WRITE_BIT) != 0 } @@ -653,7 +653,7 @@ impl Filesystem for SimpleFS { // This is important as it preserves the semantic that a file handle opened // with W_OK will never fail to truncate, even if the file has been subsequently // chmod'ed - if self.check_file_handle_write(handle) { + if Self::check_file_handle_write(handle) { if let Err(error_code) = self.truncate(inode, size, 0, 0) { reply.error(error_code); return; @@ -1408,7 +1408,7 @@ impl Filesystem for SimpleFS { ) { debug!("read() called on {inode:?} offset={offset:?} size={size:?}"); assert!(offset >= 0); - if !self.check_file_handle_read(fh) { + if !Self::check_file_handle_read(fh) { reply.error(libc::EACCES); return; } @@ -1444,7 +1444,7 @@ impl Filesystem for SimpleFS { ) { debug!("write() called with {:?} size={:?}", inode, data.len()); assert!(offset >= 0); - if !self.check_file_handle_write(fh) { + if !Self::check_file_handle_write(fh) { reply.error(libc::EACCES); return; } @@ -1872,11 +1872,11 @@ impl Filesystem for SimpleFS { debug!( "copy_file_range() called with src=({src_fh}, {src_inode}, {src_offset}) dest=({dest_fh}, {dest_inode}, {dest_offset}) size={size}" ); - if !self.check_file_handle_read(src_fh) { + if !Self::check_file_handle_read(src_fh) { reply.error(libc::EACCES); return; } - if !self.check_file_handle_write(dest_fh) { + if !Self::check_file_handle_write(dest_fh) { reply.error(libc::EACCES); return; } From af72a5f704742ee4f8b471784c651142079f513c Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sat, 6 Sep 2025 15:44:11 -0500 Subject: [PATCH 8/8] Borrow, rather than move. This `write_directory_content` function copies but doesn't move the entry data, so it is better as a borrowed parameter. --- examples/simple.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 6a69595b..eb9c7bc5 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -340,7 +340,7 @@ impl SimpleFS { } } - fn write_directory_content(&self, inode: Inode, entries: DirectoryDescriptor) { + fn write_directory_content(&self, inode: Inode, entries: &DirectoryDescriptor) { let path = Path::new(&self.data_dir) .join("contents") .join(inode.to_string()); @@ -466,7 +466,7 @@ impl SimpleFS { let mut entries = self.get_directory_content(parent).unwrap(); entries.insert(name.as_bytes().to_vec(), (inode, kind)); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); Ok(()) } @@ -502,7 +502,7 @@ impl Filesystem for SimpleFS { self.write_inode(&root); let mut entries = BTreeMap::new(); entries.insert(b".".to_vec(), (FUSE_ROOT_ID, FileKind::Directory)); - self.write_directory_content(FUSE_ROOT_ID, entries); + self.write_directory_content(FUSE_ROOT_ID, &entries); } Ok(()) } @@ -840,12 +840,12 @@ impl Filesystem for SimpleFS { let mut entries = BTreeMap::new(); entries.insert(b".".to_vec(), (inode, FileKind::Directory)); entries.insert(b"..".to_vec(), (parent, FileKind::Directory)); - self.write_directory_content(inode, entries); + self.write_directory_content(inode, &entries); } let mut entries = self.get_directory_content(parent).unwrap(); entries.insert(name.as_bytes().to_vec(), (inode, attrs.kind)); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); // TODO: implement flags reply.entry(&Duration::new(0, 0), &attrs.into(), 0); @@ -916,11 +916,11 @@ impl Filesystem for SimpleFS { let mut entries = BTreeMap::new(); entries.insert(b".".to_vec(), (inode, FileKind::Directory)); entries.insert(b"..".to_vec(), (parent, FileKind::Directory)); - self.write_directory_content(inode, entries); + self.write_directory_content(inode, &entries); let mut entries = self.get_directory_content(parent).unwrap(); entries.insert(name.as_bytes().to_vec(), (inode, FileKind::Directory)); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); reply.entry(&Duration::new(0, 0), &attrs.into(), 0); } @@ -977,7 +977,7 @@ impl Filesystem for SimpleFS { let mut entries = self.get_directory_content(parent).unwrap(); entries.remove(name.as_bytes()); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); reply.ok(); } @@ -1038,7 +1038,7 @@ impl Filesystem for SimpleFS { let mut entries = self.get_directory_content(parent).unwrap(); entries.remove(name.as_bytes()); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); reply.ok(); } @@ -1210,14 +1210,14 @@ impl Filesystem for SimpleFS { new_name.as_bytes().to_vec(), (inode_attrs.inode, inode_attrs.kind), ); - self.write_directory_content(new_parent, entries); + self.write_directory_content(new_parent, &entries); let mut entries = self.get_directory_content(parent).unwrap(); entries.insert( name.as_bytes().to_vec(), (new_inode_attrs.inode, new_inode_attrs.kind), ); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); parent_attrs.last_metadata_changed = time_now(); parent_attrs.last_modified = time_now(); @@ -1233,12 +1233,12 @@ impl Filesystem for SimpleFS { if inode_attrs.kind == FileKind::Directory { let mut entries = self.get_directory_content(inode_attrs.inode).unwrap(); entries.insert(b"..".to_vec(), (new_parent, FileKind::Directory)); - self.write_directory_content(inode_attrs.inode, entries); + self.write_directory_content(inode_attrs.inode, &entries); } if new_inode_attrs.kind == FileKind::Directory { let mut entries = self.get_directory_content(new_inode_attrs.inode).unwrap(); entries.insert(b"..".to_vec(), (parent, FileKind::Directory)); - self.write_directory_content(new_inode_attrs.inode, entries); + self.write_directory_content(new_inode_attrs.inode, &entries); } reply.ok(); @@ -1280,7 +1280,7 @@ impl Filesystem for SimpleFS { if let Ok(mut existing_inode_attrs) = self.lookup_name(new_parent, new_name) { let mut entries = self.get_directory_content(new_parent).unwrap(); entries.remove(new_name.as_bytes()); - self.write_directory_content(new_parent, entries); + self.write_directory_content(new_parent, &entries); if existing_inode_attrs.kind == FileKind::Directory { existing_inode_attrs.hardlinks = 0; @@ -1294,14 +1294,14 @@ impl Filesystem for SimpleFS { let mut entries = self.get_directory_content(parent).unwrap(); entries.remove(name.as_bytes()); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); let mut entries = self.get_directory_content(new_parent).unwrap(); entries.insert( new_name.as_bytes().to_vec(), (inode_attrs.inode, inode_attrs.kind), ); - self.write_directory_content(new_parent, entries); + self.write_directory_content(new_parent, &entries); parent_attrs.last_metadata_changed = time_now(); parent_attrs.last_modified = time_now(); @@ -1315,7 +1315,7 @@ impl Filesystem for SimpleFS { if inode_attrs.kind == FileKind::Directory { let mut entries = self.get_directory_content(inode_attrs.inode).unwrap(); entries.insert(b"..".to_vec(), (new_parent, FileKind::Directory)); - self.write_directory_content(inode_attrs.inode, entries); + self.write_directory_content(inode_attrs.inode, &entries); } reply.ok(); @@ -1805,12 +1805,12 @@ impl Filesystem for SimpleFS { let mut entries = BTreeMap::new(); entries.insert(b".".to_vec(), (inode, FileKind::Directory)); entries.insert(b"..".to_vec(), (parent, FileKind::Directory)); - self.write_directory_content(inode, entries); + self.write_directory_content(inode, &entries); } let mut entries = self.get_directory_content(parent).unwrap(); entries.insert(name.as_bytes().to_vec(), (inode, attrs.kind)); - self.write_directory_content(parent, entries); + self.write_directory_content(parent, &entries); // TODO: implement flags reply.created(