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/file | |
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/file')
-rw-r--r-- | vendor/gix-index/src/file/init.rs | 81 | ||||
-rw-r--r-- | vendor/gix-index/src/file/mod.rs | 90 | ||||
-rw-r--r-- | vendor/gix-index/src/file/verify.rs | 41 | ||||
-rw-r--r-- | vendor/gix-index/src/file/write.rs | 51 |
4 files changed, 263 insertions, 0 deletions
diff --git a/vendor/gix-index/src/file/init.rs b/vendor/gix-index/src/file/init.rs new file mode 100644 index 000000000..534f1f08b --- /dev/null +++ b/vendor/gix-index/src/file/init.rs @@ -0,0 +1,81 @@ +#![allow(unused)] + +use std::path::{Path, PathBuf}; + +use memmap2::Mmap; + +use crate::{decode, extension, File, State}; + +mod error { + + /// The error returned by [File::at()][super::File::at()]. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error("An IO error occurred while opening the index")] + Io(#[from] std::io::Error), + #[error(transparent)] + Decode(#[from] crate::decode::Error), + #[error(transparent)] + LinkExtension(#[from] crate::extension::link::decode::Error), + } +} + +pub use error::Error; + +/// Initialization +impl File { + /// Try to open the index file at `path` with `options`, assuming `object_hash` is used throughout the file, or create a new + /// index that merely exists in memory and is empty. + /// + /// Note that the `path` will not be written if it doesn't exist. + pub fn at_or_default( + path: impl Into<PathBuf>, + object_hash: gix_hash::Kind, + options: decode::Options, + ) -> Result<Self, Error> { + let path = path.into(); + Ok(match Self::at(&path, object_hash, options) { + Ok(f) => f, + Err(Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { + File::from_state(State::new(object_hash), path) + } + Err(err) => return Err(err), + }) + } + + /// Open an index file at `path` with `options`, assuming `object_hash` is used throughout the file. + pub fn at(path: impl Into<PathBuf>, object_hash: gix_hash::Kind, options: decode::Options) -> Result<Self, Error> { + let path = path.into(); + let (data, mtime) = { + // SAFETY: we have to take the risk of somebody changing the file underneath. Git never writes into the same file. + let file = std::fs::File::open(&path)?; + #[allow(unsafe_code)] + let data = unsafe { Mmap::map(&file)? }; + (data, filetime::FileTime::from_last_modification_time(&file.metadata()?)) + }; + + let (state, checksum) = State::from_bytes(&data, mtime, object_hash, options)?; + let mut file = File { + state, + path, + checksum: Some(checksum), + }; + if let Some(mut link) = file.link.take() { + link.dissolve_into(&mut file, object_hash, options)?; + } + + Ok(file) + } + + /// Consume `state` and pretend it was read from `path`, setting our checksum to `null`. + /// + /// `File` instances created like that should be written to disk to set the correct checksum via `[File::write()]`. + pub fn from_state(state: crate::State, path: impl Into<PathBuf>) -> Self { + File { + state, + path: path.into(), + checksum: None, + } + } +} diff --git a/vendor/gix-index/src/file/mod.rs b/vendor/gix-index/src/file/mod.rs new file mode 100644 index 000000000..40332abbd --- /dev/null +++ b/vendor/gix-index/src/file/mod.rs @@ -0,0 +1,90 @@ +mod impls { + use std::ops::{Deref, DerefMut}; + + use crate::{File, State}; + + impl Deref for File { + type Target = State; + + fn deref(&self) -> &Self::Target { + &self.state + } + } + + impl DerefMut for File { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.state + } + } +} + +mod impl_ { + use std::fmt::Formatter; + + use crate::{File, State}; + + impl std::fmt::Debug for File { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("File") + .field("path", &self.path.display()) + .field("checksum", &self.checksum) + .finish_non_exhaustive() + } + } + + impl From<File> for State { + fn from(f: File) -> Self { + f.state + } + } +} + +mod access { + use crate::File; + + /// Consumption + impl File { + /// Take all non-copy parts of the index. + pub fn into_parts(self) -> (crate::State, std::path::PathBuf) { + (self.state, self.path) + } + } + + /// Access + impl File { + /// The path from which the index was read or to which it is supposed to be written when used with [`File::from_state()`]. + pub fn path(&self) -> &std::path::Path { + &self.path + } + + /// The checksum over the file that was read or written to disk, or `None` if the state in memory was never serialized. + /// + /// Note that even if `Some`, it will only represent the state in memory right after reading or [writing][File::write()]. + pub fn checksum(&self) -> Option<gix_hash::ObjectId> { + self.checksum + } + } +} + +mod mutation { + use std::path::PathBuf; + + use crate::File; + + /// Mutating access + impl File { + /// Set the path at which we think we are located to the given `path`. + /// + /// This is useful to change the location of the index *once* it is written via [`write()`][File::write()]. + pub fn set_path(&mut self, path: impl Into<PathBuf>) { + self.path = path.into(); + } + } +} + +/// +pub mod init; +/// +pub mod verify; +/// +pub mod write; diff --git a/vendor/gix-index/src/file/verify.rs b/vendor/gix-index/src/file/verify.rs new file mode 100644 index 000000000..6743b37a7 --- /dev/null +++ b/vendor/gix-index/src/file/verify.rs @@ -0,0 +1,41 @@ +use std::sync::atomic::AtomicBool; + +use crate::File; + +mod error { + /// The error returned by [File::verify_integrity()][super::File::verify_integrity()]. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error("Could not read index file to generate hash")] + Io(#[from] std::io::Error), + #[error("Index checksum should have been {expected}, but was {actual}")] + ChecksumMismatch { + actual: gix_hash::ObjectId, + expected: gix_hash::ObjectId, + }, + #[error("Checksum of in-memory index wasn't computed yet")] + NoChecksum, + } +} +pub use error::Error; + +impl File { + /// Verify the integrity of the index to assure its consistency. + pub fn verify_integrity(&self) -> Result<(), Error> { + let checksum = self.checksum.ok_or(Error::NoChecksum)?; + let num_bytes_to_hash = self.path.metadata()?.len() - checksum.as_bytes().len() as u64; + let should_interrupt = AtomicBool::new(false); + let actual = gix_features::hash::bytes_of_file( + &self.path, + num_bytes_to_hash as usize, + checksum.kind(), + &mut gix_features::progress::Discard, + &should_interrupt, + )?; + (actual == checksum).then_some(()).ok_or(Error::ChecksumMismatch { + actual, + expected: checksum, + }) + } +} diff --git a/vendor/gix-index/src/file/write.rs b/vendor/gix-index/src/file/write.rs new file mode 100644 index 000000000..1e8afc07d --- /dev/null +++ b/vendor/gix-index/src/file/write.rs @@ -0,0 +1,51 @@ +use gix_features::hash; + +use crate::{write, File, Version}; + +/// The error produced by [`File::write()`]. +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum Error { + #[error(transparent)] + Io(#[from] std::io::Error), + #[error("Could not acquire lock for index file")] + AcquireLock(#[from] gix_lock::acquire::Error), + #[error("Could not commit lock for index file")] + CommitLock(#[from] gix_lock::commit::Error<gix_lock::File>), +} + +impl File { + /// Write the index to `out` with `options`, to be readable by [`File::at()`], returning the version that was actually written + /// to retain all information of this index. + pub fn write_to( + &self, + mut out: impl std::io::Write, + options: write::Options, + ) -> std::io::Result<(Version, gix_hash::ObjectId)> { + let mut hasher = hash::Write::new(&mut out, self.state.object_hash); + let version = self.state.write_to(&mut hasher, options)?; + + let hash = hasher.hash.digest(); + out.write_all(&hash)?; + Ok((version, gix_hash::ObjectId::from(hash))) + } + + /// Write ourselves to the path we were read from after acquiring a lock, using `options`. + /// + /// Note that the hash produced will be stored which is why we need to be mutable. + pub fn write(&mut self, options: write::Options) -> Result<(), Error> { + let mut lock = std::io::BufWriter::new(gix_lock::File::acquire_to_update_resource( + &self.path, + gix_lock::acquire::Fail::Immediately, + None, + )?); + let (version, digest) = self.write_to(&mut lock, options)?; + match lock.into_inner() { + Ok(lock) => lock.commit()?, + Err(err) => return Err(err.into_error().into()), + }; + self.state.version = version; + self.checksum = Some(digest); + Ok(()) + } +} |