diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix-index/src/extension/link.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-index/src/extension/link.rs')
-rw-r--r-- | vendor/gix-index/src/extension/link.rs | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/vendor/gix-index/src/extension/link.rs b/vendor/gix-index/src/extension/link.rs new file mode 100644 index 000000000..20ce9cb21 --- /dev/null +++ b/vendor/gix-index/src/extension/link.rs @@ -0,0 +1,177 @@ +use crate::{ + extension::{Link, Signature}, + util::split_at_pos, +}; + +/// The signature of the link extension. +pub const SIGNATURE: Signature = *b"link"; + +/// Bitmaps to know which entries to delete or replace, even though details are still unknown. +#[derive(Clone)] +pub struct Bitmaps { + /// A bitmap to signal which entries to delete, maybe. + pub delete: gix_bitmap::ewah::Vec, + /// A bitmap to signal which entries to replace, maybe. + pub replace: gix_bitmap::ewah::Vec, +} + +/// +pub mod decode { + + /// The error returned when decoding link extensions. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error("{0}")] + Corrupt(&'static str), + #[error("{kind} bitmap corrupt")] + BitmapDecode { + err: gix_bitmap::ewah::decode::Error, + kind: &'static str, + }, + } + + impl From<std::num::TryFromIntError> for Error { + fn from(_: std::num::TryFromIntError) -> Self { + Self::Corrupt("error in bitmap iteration trying to convert from u64 to usize") + } + } +} + +pub(crate) fn decode(data: &[u8], object_hash: gix_hash::Kind) -> Result<Link, decode::Error> { + let (id, data) = split_at_pos(data, object_hash.len_in_bytes()) + .ok_or(decode::Error::Corrupt( + "link extension too short to read share index checksum", + )) + .map(|(id, d)| (gix_hash::ObjectId::from(id), d))?; + + if data.is_empty() { + return Ok(Link { + shared_index_checksum: id, + bitmaps: None, + }); + } + + let (delete, data) = + gix_bitmap::ewah::decode(data).map_err(|err| decode::Error::BitmapDecode { kind: "delete", err })?; + let (replace, data) = + gix_bitmap::ewah::decode(data).map_err(|err| decode::Error::BitmapDecode { kind: "replace", err })?; + + if !data.is_empty() { + return Err(decode::Error::Corrupt("garbage trailing link extension")); + } + + Ok(Link { + shared_index_checksum: id, + bitmaps: Some(Bitmaps { delete, replace }), + }) +} + +impl Link { + pub(crate) fn dissolve_into( + self, + split_index: &mut crate::File, + object_hash: gix_hash::Kind, + options: crate::decode::Options, + ) -> Result<(), crate::file::init::Error> { + let shared_index_path = split_index + .path + .parent() + .expect("split index file in .git folder") + .join(format!("sharedindex.{}", self.shared_index_checksum)); + let mut shared_index = crate::File::at( + &shared_index_path, + object_hash, + crate::decode::Options { + expected_checksum: self.shared_index_checksum.into(), + ..options + }, + )?; + + if let Some(bitmaps) = self.bitmaps { + let mut split_entry_index = 0; + + let mut err = None; + bitmaps.replace.for_each_set_bit(|replace_index| { + let shared_entry = match shared_index.entries.get_mut(replace_index) { + Some(e) => e, + None => { + err = decode::Error::Corrupt("replace bitmap length exceeds shared index length - more entries in bitmap than found in shared index").into(); + return None + } + }; + + if shared_entry.flags.contains(crate::entry::Flags::REMOVE) { + err = decode::Error::Corrupt("entry is marked as both replace and delete").into(); + return None + } + + let split_entry = match split_index.entries.get(split_entry_index) { + Some(e) => e, + None => { + err = decode::Error::Corrupt("replace bitmap length exceeds split index length - more entries in bitmap than found in split index").into(); + return None + } + }; + if !split_entry.path.is_empty() { + err = decode::Error::Corrupt("paths in split index entries that are for replacement should be empty").into(); + return None + } + if shared_entry.path.is_empty() { + err = decode::Error::Corrupt("paths in shared index entries that are replaced should not be empty").into(); + return None + } + shared_entry.stat = split_entry.stat; + shared_entry.id = split_entry.id; + shared_entry.flags = split_entry.flags; + shared_entry.mode = split_entry.mode; + + split_entry_index += 1; + Some(()) + }); + if let Some(err) = err { + return Err(err.into()); + } + + let split_index_path_backing = std::mem::take(&mut split_index.path_backing); + for mut split_entry in split_index.entries.drain(split_entry_index..) { + let start = shared_index.path_backing.len(); + let split_index_path = split_entry.path.clone(); + + split_entry.path = start..start + split_entry.path.len(); + shared_index.entries.push(split_entry); + + shared_index + .path_backing + .extend_from_slice(&split_index_path_backing[split_index_path]); + } + + bitmaps.delete.for_each_set_bit(|delete_index| { + let shared_entry = match shared_index.entries.get_mut(delete_index) { + Some(e) => e, + None => { + err = decode::Error::Corrupt("delete bitmap length exceeds shared index length - more entries in bitmap than found in shared index").into(); + return None + } + }; + shared_entry.flags.insert(crate::entry::Flags::REMOVE); + Some(()) + }); + if let Some(err) = err { + return Err(err.into()); + } + + shared_index + .entries + .retain(|e| !e.flags.contains(crate::entry::Flags::REMOVE)); + + let mut shared_entries = std::mem::take(&mut shared_index.entries); + shared_entries.sort_by(|a, b| a.cmp(b, &shared_index.state)); + + split_index.entries = shared_entries; + split_index.path_backing = std::mem::take(&mut shared_index.path_backing); + } + + Ok(()) + } +} |