diff --git a/crates/spfs-cli/main/src/cmd_ls.rs b/crates/spfs-cli/main/src/cmd_ls.rs index 316e59bf19..5063e8cb63 100644 --- a/crates/spfs-cli/main/src/cmd_ls.rs +++ b/crates/spfs-cli/main/src/cmd_ls.rs @@ -166,7 +166,7 @@ impl TotalSize for Entry { if self.is_dir() { self.entries.values().map(|e| e.total_size()).sum() } else { - self.size + self.size() } } } diff --git a/crates/spfs-proto/schema/spfs.fbs b/crates/spfs-proto/schema/spfs.fbs index 071aa1de1c..8e42506ff8 100644 --- a/crates/spfs-proto/schema/spfs.fbs +++ b/crates/spfs-proto/schema/spfs.fbs @@ -54,6 +54,7 @@ table Entry { kind:EntryKind; object:Digest (required); mode:uint32; + // Size should only be present for blob entries size:uint64; name:string (required); } diff --git a/crates/spfs-vfs/src/fuse.rs b/crates/spfs-vfs/src/fuse.rs index f76d11e57d..78c885df4c 100644 --- a/crates/spfs-vfs/src/fuse.rs +++ b/crates/spfs-vfs/src/fuse.rs @@ -115,9 +115,9 @@ impl Filesystem { kind, object, mode, - size, entries, user_data: _, + legacy_size, } = entry; let inode = self.allocate_inode(); @@ -129,9 +129,9 @@ impl Filesystem { kind, object, mode, - size, entries, user_data: inode, + legacy_size, }); self.inodes.insert(inode, Arc::clone(&entry)); entry @@ -159,15 +159,15 @@ impl Filesystem { fn attr_from_entry(&self, entry: &Entry) -> FileAttr { let kind = match entry.kind { - EntryKind::Blob if entry.is_symlink() => FileType::Symlink, - EntryKind::Blob => FileType::RegularFile, + EntryKind::Blob(_) if entry.is_symlink() => FileType::Symlink, + EntryKind::Blob(_) => FileType::RegularFile, EntryKind::Tree => FileType::Directory, EntryKind::Mask => unreachable!(), }; let size = if entry.is_dir() { entry.entries.len() as u64 } else { - entry.size + entry.size() }; FileAttr { ino: entry.user_data, @@ -222,7 +222,7 @@ impl Filesystem { let blocks = self .inodes .iter() - .map(|i| (i.value().size / Self::BLOCK_SIZE as u64) + 1) + .map(|i| (i.value().size() / Self::BLOCK_SIZE as u64) + 1) .sum(); let files = self .inodes @@ -255,7 +255,7 @@ impl Filesystem { tracing::trace!("lookup {name} in {}", parent.key()); match parent.kind { - EntryKind::Blob => { + EntryKind::Blob(_) => { reply.error(libc::ENOTDIR); return; } @@ -349,7 +349,7 @@ impl Filesystem { reply.error(libc::ENOENT); return; } - EntryKind::Blob => &entry.object, + EntryKind::Blob(_) => &entry.object, }; let mut handle = None; @@ -503,7 +503,7 @@ impl Filesystem { }; let handle = match entry.kind { - EntryKind::Blob => { + EntryKind::Blob(_) => { reply.error(libc::ENOTDIR); return; } @@ -548,8 +548,8 @@ impl Filesystem { } for (name, entry) in remaining { let kind = match entry.kind { - EntryKind::Blob if entry.is_symlink() => FileType::Symlink, - EntryKind::Blob => FileType::RegularFile, + EntryKind::Blob(_) if entry.is_symlink() => FileType::Symlink, + EntryKind::Blob(_) => FileType::RegularFile, EntryKind::Tree => FileType::Directory, EntryKind::Mask => continue, }; diff --git a/crates/spfs/src/commit.rs b/crates/spfs/src/commit.rs index 0860a198e5..63a3acfb4d 100644 --- a/crates/spfs/src/commit.rs +++ b/crates/spfs/src/commit.rs @@ -395,7 +395,7 @@ impl tracking::ComputeManifestReporter for ConsoleCommitReporter { bars.entries.inc(1); if entry.kind.is_blob() { bars.blobs.inc_length(1); - bars.bytes.inc_length(entry.size); + bars.bytes.inc_length(entry.size()); } } } @@ -403,8 +403,13 @@ impl tracking::ComputeManifestReporter for ConsoleCommitReporter { impl CommitReporter for ConsoleCommitReporter { fn committed_blob(&self, result: &CommitBlobResult) { let bars = self.get_bars(); - bars.bytes.inc(result.node().entry.size); - bars.blobs.inc(1); + if result.node().entry.kind.is_blob() { + bars.bytes.inc(result.node().entry.size()); + bars.blobs.inc(1); + } else { + debug_assert!(false, "committed_blob called with non-blob entry"); + bars.blobs.inc(1); + } } } diff --git a/crates/spfs/src/graph/entry.rs b/crates/spfs/src/graph/entry.rs index 15e45a6251..50d4deb91c 100644 --- a/crates/spfs/src/graph/entry.rs +++ b/crates/spfs/src/graph/entry.rs @@ -70,7 +70,7 @@ impl<'buf> Entry<'buf> { name, entry.kind, entry.mode, - entry.size, + entry.size_for_legacy_encode(), &entry.object, ) } @@ -82,7 +82,7 @@ impl<'buf> Entry<'buf> { pub fn kind(&self) -> tracking::EntryKind { match self.0.kind() { - spfs_proto::EntryKind::Blob => tracking::EntryKind::Blob, + spfs_proto::EntryKind::Blob => tracking::EntryKind::Blob(self.0.size_()), spfs_proto::EntryKind::Tree => tracking::EntryKind::Tree, spfs_proto::EntryKind::Mask => tracking::EntryKind::Mask, _ => unreachable!("internally valid entry buffer"), @@ -96,7 +96,10 @@ impl<'buf> Entry<'buf> { #[inline] pub fn size(&self) -> u64 { - self.0.size_() + match self.0.kind() { + spfs_proto::EntryKind::Blob => self.0.size_(), + _ => 0, + } } #[inline] @@ -118,6 +121,15 @@ impl<'buf> Entry<'buf> { pub fn is_regular_file(&self) -> bool { unix_mode::is_file(self.mode()) } + + /// Return the size of the blob or the legacy size for non-blobs. + /// + /// This is required to preserve backwards compatibility with how digests + /// are calculated for non-blob entries. + #[inline] + pub fn size_for_legacy_encode(&self) -> u64 { + self.0.size_() + } } impl<'buf> std::fmt::Display for Entry<'buf> { @@ -148,7 +160,8 @@ impl<'buf1, 'buf2> PartialOrd> for Entry<'buf1> { impl<'buf> Ord for Entry<'buf> { fn cmp(&self, other: &Entry<'buf>) -> std::cmp::Ordering { - if self.kind() == other.kind() { + // Note that the Entry's size does not factor into the comparison. + if self.0.kind() == other.0.kind() { self.name().cmp(other.name()) } else { self.kind().cmp(&other.kind()) @@ -171,7 +184,7 @@ impl<'buf> Entry<'buf> { encoding::write_digest(&mut writer, self.object())?; self.kind().encode(&mut writer)?; encoding::write_uint64(&mut writer, self.mode() as u64)?; - encoding::write_uint64(&mut writer, self.size())?; + encoding::write_uint64(&mut writer, self.size_for_legacy_encode())?; encoding::write_string(writer, self.name())?; Ok(()) } @@ -182,10 +195,13 @@ impl<'buf> Entry<'buf> { ) -> Result>> { // fields in the same order as above let object = encoding::read_digest(&mut reader)?; - let kind = tracking::EntryKind::decode(&mut reader)?; + let mut kind = tracking::EntryKind::decode(&mut reader)?; let mode = encoding::read_uint64(&mut reader)? as u32; let size = encoding::read_uint64(&mut reader)?; let name = encoding::read_string(reader)?; + if kind.is_blob() { + kind = tracking::EntryKind::Blob(size); + } Ok(Self::build(builder, &name, kind, mode, size, &object)) } } @@ -201,6 +217,36 @@ pub struct EntryBuf(Box<[u8]>); #[cfg(test)] impl EntryBuf { pub fn build( + name: &str, + kind: tracking::EntryKind, + mode: u32, + object: &encoding::Digest, + ) -> Self { + crate::graph::BUILDER.with_borrow_mut(|builder| { + let name = builder.create_string(name); + let e = spfs_proto::Entry::create( + builder, + &EntryArgs { + kind: kind.into(), + object: Some(object), + mode, + size_: { + match kind { + tracking::EntryKind::Blob(size) => size, + _ => 0, + } + }, + name: Some(name), + }, + ); + builder.finish_minimal(e); + let bytes = builder.finished_data().into(); + builder.reset(); + Self(bytes) + }) + } + + pub fn build_with_legacy_size( name: &str, kind: tracking::EntryKind, mode: u32, @@ -215,7 +261,12 @@ impl EntryBuf { kind: kind.into(), object: Some(object), mode, - size_: size, + size_: { + match kind { + tracking::EntryKind::Blob(size) => size, + _ => size, + } + }, name: Some(name), }, ); diff --git a/crates/spfs/src/graph/entry_test.rs b/crates/spfs/src/graph/entry_test.rs index 979a536d74..094d40a5ff 100644 --- a/crates/spfs/src/graph/entry_test.rs +++ b/crates/spfs/src/graph/entry_test.rs @@ -12,7 +12,7 @@ use crate::tracking::EntryKind; #[rstest(entry, digest, case( - EntryBuf::build( + EntryBuf::build_with_legacy_size( "testcase", EntryKind::Tree, 0o40755, @@ -24,9 +24,8 @@ use crate::tracking::EntryKind; case( EntryBuf::build( "swig_full_names.xsl", - EntryKind::Blob, + EntryKind::Blob(3293), 0o100644, - 3293, &"ZD25L3AN5E3LTZ6MDQOIZUV6KRV5Y4SSXRE4YMYZJJ3PXCQ3FMQA====".parse().unwrap(), ), "GP7DYE22DYLH3I5MB33PW5Z3AZXZIBGOND7MX65KECBMHVMXBUHQ====".parse().unwrap(), diff --git a/crates/spfs/src/graph/manifest.rs b/crates/spfs/src/graph/manifest.rs index 8f26083554..fa4d518db6 100644 --- a/crates/spfs/src/graph/manifest.rs +++ b/crates/spfs/src/graph/manifest.rs @@ -92,10 +92,10 @@ impl Manifest { let mut new_entry = tracking::Entry { kind: entry.kind(), mode: entry.mode(), - size: entry.size(), entries: Default::default(), object: *entry.object(), user_data: (), + legacy_size: entry.size_for_legacy_encode(), }; if entry.kind().is_tree() { new_entry.object = encoding::NULL_DIGEST.into(); @@ -275,7 +275,7 @@ impl ManifestBuilder { node.path.as_str(), node.entry.kind, node.entry.mode, - node.entry.size, + node.entry.size_for_legacy_encode(), &sub_root_digest, ) } diff --git a/crates/spfs/src/graph/manifest_test.rs b/crates/spfs/src/graph/manifest_test.rs index 49f4f08595..e14884ba00 100644 --- a/crates/spfs/src/graph/manifest_test.rs +++ b/crates/spfs/src/graph/manifest_test.rs @@ -11,15 +11,13 @@ use crate::{encoding, tracking}; fn test_entry_blobs_compare_name() { let a = EntryBuf::build( "a", - tracking::EntryKind::Blob, - 0, + tracking::EntryKind::Blob(0), 0, &encoding::EMPTY_DIGEST.into(), ); let b = EntryBuf::build( "b", - tracking::EntryKind::Blob, - 0, + tracking::EntryKind::Blob(0), 0, &encoding::EMPTY_DIGEST.into(), ); @@ -33,14 +31,12 @@ fn test_entry_trees_compare_name() { "a", tracking::EntryKind::Tree, 0, - 0, &encoding::EMPTY_DIGEST.into(), ); let b = EntryBuf::build( "b", tracking::EntryKind::Tree, 0, - 0, &encoding::EMPTY_DIGEST.into(), ); assert!(a.as_entry() < b.as_entry()); @@ -51,8 +47,7 @@ fn test_entry_trees_compare_name() { fn test_entry_compare_kind() { let blob = EntryBuf::build( "a", - tracking::EntryKind::Blob, - 0, + tracking::EntryKind::Blob(0), 0, &encoding::EMPTY_DIGEST.into(), ); @@ -60,7 +55,6 @@ fn test_entry_compare_kind() { "b", tracking::EntryKind::Tree, 0, - 0, &encoding::EMPTY_DIGEST.into(), ); assert!(tree.as_entry() > blob.as_entry()); @@ -71,8 +65,7 @@ fn test_entry_compare_kind() { fn test_entry_compare() { let root_file = EntryBuf::build( "file", - tracking::EntryKind::Blob, - 0, + tracking::EntryKind::Blob(0), 0, &encoding::NULL_DIGEST.into(), ); @@ -80,7 +73,6 @@ fn test_entry_compare() { "xdir", tracking::EntryKind::Tree, 0, - 0, &encoding::NULL_DIGEST.into(), ); assert!(root_dir.as_entry() > root_file.as_entry()); diff --git a/crates/spfs/src/graph/object.rs b/crates/spfs/src/graph/object.rs index 8789135ca5..59a9ba6f0b 100644 --- a/crates/spfs/src/graph/object.rs +++ b/crates/spfs/src/graph/object.rs @@ -162,7 +162,7 @@ impl Object { } Enum::Manifest(object) => { for node in object.to_tracking_manifest().walk_abs("/spfs") { - total_size += node.entry.size + total_size += node.entry.size() } } Enum::Blob(object) => total_size += object.size(), diff --git a/crates/spfs/src/graph/tree.rs b/crates/spfs/src/graph/tree.rs index 11febb57b0..7d5fc264d5 100644 --- a/crates/spfs/src/graph/tree.rs +++ b/crates/spfs/src/graph/tree.rs @@ -114,7 +114,7 @@ impl TreeBuf { kind: entry.kind().into(), object: Some(entry.object()), mode: entry.mode(), - size_: entry.size(), + size_: entry.size_for_legacy_encode(), name: Some(name), }, ) diff --git a/crates/spfs/src/graph/tree_test.rs b/crates/spfs/src/graph/tree_test.rs index 9d7c037dc6..6e95fa9692 100644 --- a/crates/spfs/src/graph/tree_test.rs +++ b/crates/spfs/src/graph/tree_test.rs @@ -14,7 +14,7 @@ use crate::tracking::EntryKind; #[rstest] #[case( TreeBuf::build(vec![ - EntryBuf::build( + EntryBuf::build_with_legacy_size( "pkg", EntryKind::Tree, 0o40755, @@ -28,19 +28,17 @@ use crate::tracking::EntryKind; TreeBuf::build(vec![ EntryBuf::build( ".helmignore", - EntryKind::Blob, + EntryKind::Blob(342), 0o100644, - 342, &"NJDVDBWMXKU2BJG6L2LKLS3N3T47VUGXNPBY4BCHBLEEIRNSDILA====".parse().unwrap(), ), EntryBuf::build( "Chart.yaml", - EntryKind::Blob, + EntryKind::Blob(911), 0o100644, - 911, &"ULAX2BMLX3WKVI7YKRQLJEQDEWJRSDPCFPZPGBJCIQZJ4FIVZIKA====".parse().unwrap(), ), - EntryBuf::build( + EntryBuf::build_with_legacy_size( "templates", EntryKind::Tree, 0o40755, @@ -49,9 +47,8 @@ use crate::tracking::EntryKind; ), EntryBuf::build( "values.yaml", - EntryKind::Blob, + EntryKind::Blob(1699), 0o100644, - 1699, &"IZFXS6UQJTHYBVYK3KYPPZC3FYX6NL3L3MWXAJUULAJMFTGZPODQ====".parse().unwrap(), ), ]), diff --git a/crates/spfs/src/io.rs b/crates/spfs/src/io.rs index 756edf9d68..17d6ee5691 100644 --- a/crates/spfs/src/io.rs +++ b/crates/spfs/src/io.rs @@ -87,8 +87,8 @@ pub fn format_diffs<'a, U1: 'a, U2: 'a>( if a.object != b.object { abouts.push("content".to_string()); } - if a.size != b.size { - abouts.push(format!("size {{{}=>{}}}", a.size, b.size)); + if a.size() != b.size() { + abouts.push(format!("size {{{}=>{}}}", a.size(), b.size())); } } let about = if !abouts.is_empty() { @@ -188,7 +188,7 @@ pub async fn pretty_print_filepath( unix_mode::to_string(entry.mode), entry.kind.to_string().green(), format_digest(entry.object, digest_format.clone()).await?, - format_size(entry.size), + format_size(entry.size()), ); } } diff --git a/crates/spfs/src/proto/conversions.rs b/crates/spfs/src/proto/conversions.rs index c3ec42321b..11cf56b838 100644 --- a/crates/spfs/src/proto/conversions.rs +++ b/crates/spfs/src/proto/conversions.rs @@ -307,7 +307,7 @@ impl<'buf> From<&graph::Entry<'buf>> for super::Entry { fn from(source: &graph::Entry) -> Self { let kind = match source.kind() { tracking::EntryKind::Tree => super::EntryKind::Tree as i32, - tracking::EntryKind::Blob => super::EntryKind::Blob as i32, + tracking::EntryKind::Blob(_) => super::EntryKind::Blob as i32, tracking::EntryKind::Mask => super::EntryKind::Mask as i32, }; Self { diff --git a/crates/spfs/src/storage/fs/renderer_unix.rs b/crates/spfs/src/storage/fs/renderer_unix.rs index a8d7d8fef1..49a2d68e58 100644 --- a/crates/spfs/src/storage/fs/renderer_unix.rs +++ b/crates/spfs/src/storage/fs/renderer_unix.rs @@ -498,7 +498,7 @@ where res.map(|_| None).map_err(|err| err.wrap(format!("render_into_dir '{}'", entry.name()))) } tracking::EntryKind::Mask => Ok(None), - tracking::EntryKind::Blob => { + tracking::EntryKind::Blob(_) => { self.render_blob(root_dir_fd, entry, render_type).await.map(Some).map_err(|err| err.wrap(format!("render blob '{}'", entry.name()))) } }.map(|render_blob_result_opt| (entry, render_blob_result_opt)) diff --git a/crates/spfs/src/tracking/entry.rs b/crates/spfs/src/tracking/entry.rs index 386318d92d..7595f5c730 100644 --- a/crates/spfs/src/tracking/entry.rs +++ b/crates/spfs/src/tracking/entry.rs @@ -16,8 +16,8 @@ mod entry_test; pub enum EntryKind { /// directory / node Tree, - /// file / leaf - Blob, + /// file / leaf with size + Blob(u64), /// removed entry / node or leaf Mask, } @@ -26,7 +26,11 @@ impl std::fmt::Display for EntryKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Tree => f.write_str("tree"), - Self::Blob => f.write_str("file"), + Self::Blob(_) => { + // This is currently used in encoding and the size is not + // included. + f.write_str("file") + } Self::Mask => f.write_str("mask"), } } @@ -53,7 +57,7 @@ impl EntryKind { matches!(self, Self::Tree) } pub fn is_blob(&self) -> bool { - matches!(self, Self::Blob) + matches!(self, Self::Blob(_)) } pub fn is_mask(&self) -> bool { matches!(self, Self::Mask) @@ -66,7 +70,7 @@ impl FromStr for EntryKind { fn from_str(s: &str) -> Result { match s { "tree" => Ok(Self::Tree), - "file" => Ok(Self::Blob), + "file" => Ok(Self::Blob(0)), "mask" => Ok(Self::Mask), kind => Err(format!("invalid entry kind: {kind}").into()), } @@ -76,7 +80,7 @@ impl FromStr for EntryKind { impl From for spfs_proto::EntryKind { fn from(val: EntryKind) -> spfs_proto::EntryKind { match val { - EntryKind::Blob => spfs_proto::EntryKind::Blob, + EntryKind::Blob(_) => spfs_proto::EntryKind::Blob, EntryKind::Tree => spfs_proto::EntryKind::Tree, EntryKind::Mask => spfs_proto::EntryKind::Mask, } @@ -105,9 +109,10 @@ pub struct Entry { pub kind: EntryKind, pub object: encoding::Digest, pub mode: u32, - pub size: u64, pub entries: std::collections::HashMap>, pub user_data: T, + /// The size associated with non-blob entries. + pub legacy_size: u64, } impl std::fmt::Debug for Entry @@ -121,14 +126,13 @@ where kind, object, mode, - size, entries, user_data, + legacy_size: _, } = self; f.debug_struct("Entry") .field("kind", kind) .field("mode", &format!("{mode:#06o}")) - .field("size", size) .field("object", object) .field("entries", entries) .field("user_data", user_data) @@ -144,18 +148,15 @@ impl PartialEq> for Entry { kind, object, mode, - size, entries, user_data: _, + legacy_size: _, } = other; - if self.kind != *kind || self.mode != *mode || self.object != *object { - return false; - } - // Only compare size for blobs. The size captured for directories can - // vary based on the filesystem in use or if fuse is in use, and - // a rendered manifest may not have the expected size even if it is - // unmodified. - if self.kind.is_blob() && self.size != *size { + if self.kind != *kind + || self.mode != *mode + || self.size() != other.size() + || self.object != *object + { return false; } if self.entries.len() != entries.len() { @@ -192,21 +193,21 @@ impl Entry { kind: EntryKind::Mask, object: encoding::NULL_DIGEST.into(), mode: 0o0777, // for backwards-compatible hashing - size: 0, entries: Default::default(), user_data, + legacy_size: 0, } } /// Create an entry that represents an empty symlink pub fn empty_symlink_with_data(user_data: T) -> Self { Self { - kind: EntryKind::Blob, + kind: EntryKind::Blob(0), object: encoding::EMPTY_DIGEST.into(), mode: 0o0120777, - size: 0, entries: Default::default(), user_data, + legacy_size: 0, } } @@ -217,9 +218,9 @@ impl Entry { kind: EntryKind::Tree, object: encoding::NULL_DIGEST.into(), mode: 0o0040777, - size: 0, entries: Default::default(), user_data, + legacy_size: 0, } } @@ -227,12 +228,33 @@ impl Entry { /// directory with fully open permissions pub fn empty_file_with_open_perms_with_data(user_data: T) -> Self { Self { - kind: EntryKind::Blob, + kind: EntryKind::Blob(0), object: encoding::EMPTY_DIGEST.into(), mode: 0o0100777, - size: 0, entries: Default::default(), user_data, + legacy_size: 0, + } + } + + /// Return the size of the blob; size is meaningless for other entry types. + #[inline] + pub fn size(&self) -> u64 { + match self.kind { + EntryKind::Blob(size) => size, + _ => 0, + } + } + + /// Return the size of the blob or the legacy size for non-blobs. + /// + /// This is required to preserve backwards compatibility with how digests + /// are calculated for non-blob entries. + #[inline] + pub fn size_for_legacy_encode(&self) -> u64 { + match self.kind { + EntryKind::Blob(size) => size, + _ => self.legacy_size, } } } @@ -289,13 +311,13 @@ impl Entry { kind: self.kind, object: self.object, mode: self.mode, - size: self.size, entries: self .entries .into_iter() .map(|(n, e)| (n, e.strip_user_data())) .collect(), user_data: (), + legacy_size: self.legacy_size, } } @@ -305,13 +327,13 @@ impl Entry { kind: self.kind, object: self.object, mode: self.mode, - size: self.size, entries: self .entries .into_iter() .map(|(n, e)| (n, e.and_user_data(user_data.clone()))) .collect(), user_data, + legacy_size: self.legacy_size, } } @@ -322,13 +344,13 @@ impl Entry { kind: self.kind, object: self.object, mode: self.mode, - size: self.size, entries: self .entries .into_iter() .map(|(n, e)| (n, e.with_user_data(T1::default()))) .collect(), user_data, + legacy_size: self.legacy_size, } } } @@ -342,7 +364,6 @@ where self.object = other.object; self.mode = other.mode; if !self.kind.is_tree() { - self.size = other.size; return; } @@ -357,6 +378,5 @@ where self.entries.insert(name.clone(), node.clone()); } } - self.size = self.entries.len() as u64; } } diff --git a/crates/spfs/src/tracking/manifest.rs b/crates/spfs/src/tracking/manifest.rs index 2419ea6964..f4dda5e961 100644 --- a/crates/spfs/src/tracking/manifest.rs +++ b/crates/spfs/src/tracking/manifest.rs @@ -601,7 +601,6 @@ where while let Some((file_name, entry)) = stream.try_next().await? { tree_node.entries.insert(file_name, entry); } - tree_node.size = tree_node.entries.len() as u64; Ok(tree_node) } @@ -650,6 +649,17 @@ where let mut entry: Entry; let file_type = stat_result.file_type(); + + let file_size: u64; + #[cfg(unix)] + { + file_size = stat_result.size(); + } + #[cfg(windows)] + { + file_size = stat_result.file_size(); + } + if file_type.is_symlink() { let _permit = self.blob_semaphore.acquire().await; debug_assert!( @@ -669,6 +679,7 @@ where })? .into_bytes(); entry = Entry::empty_symlink(); + entry.kind = EntryKind::Blob(file_size); entry.object = self .hasher .hash_blob(Box::pin(std::io::Cursor::new(link_target))) @@ -693,17 +704,16 @@ where })?) .with_permissions(entry.mode); + entry.kind = EntryKind::Blob(file_size); entry.object = self.hasher.hash_blob(Box::pin(reader)).await?; } #[cfg(unix)] { entry.mode = stat_result.mode(); - entry.size = stat_result.size(); } #[cfg(windows)] { - entry.size = stat_result.file_size(); // use the same default posix permissions as git uses // for files created on windows entry.mode = 0o644; diff --git a/crates/spk-build/src/build/binary.rs b/crates/spk-build/src/build/binary.rs index bbd8e824c5..7c5baea732 100644 --- a/crates/spk-build/src/build/binary.rs +++ b/crates/spk-build/src/build/binary.rs @@ -376,7 +376,7 @@ where continue; }; let entry = environment_filesystem.mknod(&path, entry)?; - if !matches!(entry.kind, EntryKind::Blob) { + if !matches!(entry.kind, EntryKind::Blob(_)) { continue; } diff --git a/crates/spk-build/src/build/binary_test.rs b/crates/spk-build/src/build/binary_test.rs index 7c6401b5e5..66ac53c167 100644 --- a/crates/spk-build/src/build/binary_test.rs +++ b/crates/spk-build/src/build/binary_test.rs @@ -30,12 +30,12 @@ fn test_split_manifest_permissions() { .mknod( "bin/runme", Entry { - kind: EntryKind::Blob, + kind: EntryKind::Blob(0), object: EMPTY_DIGEST.into(), mode: 0o555, - size: 0, entries: Default::default(), user_data: (), + legacy_size: 0, }, ) .unwrap(); diff --git a/crates/spk-cli/cmd-du/src/cmd_du.rs b/crates/spk-cli/cmd-du/src/cmd_du.rs index c5b0962921..c772ac561e 100644 --- a/crates/spk-cli/cmd-du/src/cmd_du.rs +++ b/crates/spk-cli/cmd-du/src/cmd_du.rs @@ -515,7 +515,7 @@ impl DiskUsage for Entry { if entry.kind.is_blob() { yield EntryDiskUsage::new( updated_paths.clone(), - entry.size, + entry.size(), entry.object, ) }