diff --git a/Cargo.lock b/Cargo.lock index fb8ad5a..330acdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,55 +75,37 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -147,9 +129,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "generic-array" @@ -174,12 +156,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - [[package]] name = "iana-time-zone" version = "0.1.59" @@ -205,18 +181,18 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.147" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "log" @@ -226,22 +202,14 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "md-5" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "num-traits" version = "0.2.17" @@ -251,16 +219,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "once_cell" version = "1.19.0" @@ -269,27 +227,27 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -297,27 +255,19 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -326,9 +276,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -337,9 +287,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -348,18 +298,18 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" @@ -375,9 +325,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -385,9 +335,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", @@ -400,9 +350,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -410,9 +360,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", @@ -423,9 +373,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index 164b289..fd5ec08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ color = ["dep:termcolor"] chrono = "0.4" libc = "0.2" md-5 = "0.10" -rayon = { version = "1.7", optional = true } +rayon = { version = "1.8", optional = true } sha1 = "0.10" sha2 = "0.10" termcolor = { version = "1.4", optional = true } diff --git a/src/checksum.rs b/src/checksum.rs index bc3acbc..c7e1395 100644 --- a/src/checksum.rs +++ b/src/checksum.rs @@ -6,11 +6,26 @@ use { }, }; +/// A hashing algorithm used for checking file integrity #[derive(Clone, Copy, Debug)] pub enum Algorithm { + /// The [md5](https://www.ietf.org/rfc/rfc1321.txt) hash is + /// a widely deployed fast hash included for completeness. + /// As md5 is not cryptographically secure and collisions have + /// been proven to occur, the newer sha\[x\] algorithms are to + /// be preferred Md5, + /// The [sha1](https://datatracker.ietf.org/doc/html/rfc3174) + /// hash is competitive in speed to md5 while having significantly + /// lower possibility of hash collision. Use this hash method if + /// you want goot file integrity checking coupled with low overhead. Sha1, + /// The [sha256](https://tools.ietf.org/html/rfc6234) hash is + /// a cryptographically secure hash that is stronger than both + /// md5 and sha1. Use this hash when the importance of file + /// integrity far outweighs performance considerations. Sha256, + /// Do not use file integrity checks Skip, } @@ -31,7 +46,8 @@ impl FromStr for Algorithm { /// Optional checksumming for individual files #[derive(Debug)] pub enum Checksum { - /// Md5 checksumming, fastest + /// Md5 checksumming, fastest, but collisions have occurred. Not recommended + /// for production use. Md5([u8; 16]), /// Sha1 checksumming. On par with md5. Sha1([u8; 20]), @@ -45,6 +61,9 @@ pub enum Checksum { } impl Checksum { + /// Reads a `Checksum` item into memory from a byte stream + /// # Errors + /// Returns an `Error` if io fails or the archive is incorrectly formatted pub(crate) fn read(reader: &mut T) -> Result { let mut buf = [0; 1]; reader.read_exact(&mut buf)?; @@ -68,6 +87,9 @@ impl Checksum { } } + /// Writes a `Checksum` into a byte stream + /// # Errors + /// Returns `Error` if io fails pub(crate) fn write(&self, writer: &mut T) -> Result<(), Error> { match self { Self::Md5(sum) => { diff --git a/src/file.rs b/src/file.rs index 706c11e..2c7d466 100644 --- a/src/file.rs +++ b/src/file.rs @@ -18,6 +18,10 @@ pub struct File { } impl File { + /// Read a `File` structure from a stream of bytes + /// # Errors + /// Can return `Error` if io fails or the byte stream is not a valid + /// **Haggis** archive pub(crate) fn read(reader: &mut T) -> Result { let mut len = [0; 8]; reader.read_exact(&mut len)?; @@ -77,6 +81,9 @@ impl File { } } + /// Writes a `File` structure into a stream of bytes + /// # Errors + /// Can return `Error` if io fails pub(crate) fn write(&self, writer: &mut T) -> Result<(), Error> { writer.write_all(&self.len.to_le_bytes())?; Checksum::write(&self.checksum, writer)?; diff --git a/src/lib.rs b/src/lib.rs index 2f3b977..37a623e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,9 @@ pub fn stream_archive( Ok(()) } +/// A message to be passed to another thread when a `Node` is created or saved. +/// Useful when creating a `Node` in a background thread and displaying progress +/// in the main thread #[cfg(feature = "parallel")] #[derive(Debug)] pub enum Message { diff --git a/src/listing.rs b/src/listing.rs index 897a806..0001e49 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -14,15 +14,32 @@ use { }, }; +/// An item representing the `Filetype` of a `Node` without +/// including a file's actual data or checksum. #[derive(Debug, PartialEq, Eq)] pub enum Kind { + /// A regular file. The associated `u64` represents the files + /// size in bytes. Normal(u64), + /// A hard link to another member of this archive. The associated + /// `String` represents the target of the link HardLink(String), + /// A symlink to another file. The associated `String` represents + /// the target of the link. SoftLink(String), + /// A directory entry Directory, + /// A character (buffered) device file. The associated `Special` + /// struct represents the **major** and **minor** numbers of the + /// device file. Character(Special), + /// A block (non-buffered) device file. The associated `Special` + /// struct represents the **major** and **minor** numbers of the + /// device file. Block(Special), + /// A named pipe Fifo, + /// The end of the archive Eof, } @@ -42,6 +59,8 @@ impl From for Kind { } impl Kind { + /// Reads an item from a stream of bytes. The stream can be anything implementing + /// both `Read` and `Seek` #[allow(clippy::cast_possible_wrap)] fn read(reader: &mut R, flag: Flag) -> Result { match flag { @@ -102,6 +121,17 @@ impl Kind { } } +/// An item representing a `Node` with all relavent metadata minus +/// the bytes making up the file and the file's checksum. Useful +/// for examining the contents of an archive by printing file listings. +/// > Note: Because this type can be read from an archive while skipping over +/// > the bytes making up the file's contents and checksum, it can be created +/// > faster than a `Node` and takes up less space in memory. However, it may +/// > not always be possible to create a `Listing` directly, as in the case +/// > where the underlying byte stream does not implement `Seek`, such as with +/// > a zstd compressed archive. In this case, a `Node` can be read from the +/// > stream and converted to a `Listing` using `From`, which will still save +/// > on overall memory usage when listing all files in an archive. #[derive(Debug, PartialEq, Eq)] pub struct Listing { pub name: String, @@ -262,6 +292,11 @@ impl Listing { }) } + /// Prints a line with relavent metadata included, + /// colorizing the filename based on the filetype. + /// Similar to GNU `ls --long --color auto` + /// # Errors + /// Can return an `Error` if stdout is unavailable #[allow(clippy::cast_possible_wrap)] #[cfg(feature = "color")] pub fn print_color(&self) -> Result<(), Error> { @@ -363,6 +398,10 @@ impl Listing { Ok(()) } + /// Prints just the filename representing the `Listing` item, + /// coloring each line based on the filetype + /// # Errors + /// Can return an `Error` if stdout is unavailable #[cfg(feature = "color")] pub fn print_color_simple(&self) -> Result<(), Error> { let mut stdout = StandardStream::stdout(ColorChoice::Auto); diff --git a/src/listing_stream.rs b/src/listing_stream.rs index 4509b6c..ce336af 100644 --- a/src/listing_stream.rs +++ b/src/listing_stream.rs @@ -6,6 +6,8 @@ use { }, }; +/// An iterator over `Listing` items, used for displaying the contents of a +/// *Haggis* archive #[derive(Debug)] pub struct ListingStream { pub length: u32, @@ -28,6 +30,12 @@ impl Iterator for ListingStream { } impl ListingStream { + /// Creates a new `ListingStream` from the given reader, + /// which should be a stream of bytes making up a valid Haggis + /// archive. + ///# Errors + /// Can return `Error` if an io error occurs or if the arvhice + /// is incorrectly formatted pub fn new(mut reader: R) -> Result { let mut buf = [0; 11]; reader.read_exact(&mut buf)?; @@ -39,6 +47,11 @@ impl ListingStream { } } + /// Creates a `Vec` of `Listing` structs representing every `Node` + /// making up the archive + /// # Errors + /// Can return `Error` if an io error occurs or if the archive is + /// incorrectly formatted pub fn list(&mut self) -> Result, Error> { let mut list = vec![]; for listing in self { diff --git a/src/nix/mod.rs b/src/nix/mod.rs index d370346..2f2849b 100644 --- a/src/nix/mod.rs +++ b/src/nix/mod.rs @@ -10,6 +10,8 @@ pub fn geteuid() -> u32 { unsafe { libc::geteuid() } } +/// A wrapper around the libc **chown** function, used for changing file +/// ownership #[allow(clippy::similar_names)] pub fn chown(path: &str, uid: u32, gid: u32) -> Result<(), Error> { let ret = unsafe { libc::chown(CString::new(path)?.as_ptr(), uid, gid) }; @@ -20,6 +22,8 @@ pub fn chown(path: &str, uid: u32, gid: u32) -> Result<(), Error> { } } +/// A wrapper around the libc **chmod** function, used for changing file +/// permissions #[cfg(target_os = "linux")] pub fn chmod(path: &str, mode: u32) -> Result<(), Error> { let ret = unsafe { libc::chmod(CString::new(path)?.as_ptr(), mode) }; @@ -30,6 +34,8 @@ pub fn chmod(path: &str, mode: u32) -> Result<(), Error> { } } +/// A wrapper around the libc **chmod** function, used for changing file +/// permissions #[cfg(target_os = "freebsd")] pub fn chmod(path: &str, mode: u32) -> Result<(), Error> { let ret = unsafe { libc::chmod(CString::new(path)?.as_ptr(), mode.try_into()?) }; @@ -40,6 +46,7 @@ pub fn chmod(path: &str, mode: u32) -> Result<(), Error> { } } +/// A wrapper around the libc **mkfifo** function, for creating named pipes #[cfg(target_os = "linux")] pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> { let ret = unsafe { libc::mkfifo(CString::new(path)?.as_ptr(), mode) }; @@ -50,6 +57,7 @@ pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> { } } +/// A wrapper around the libc **mkfifo** function, for creating named pipes #[cfg(target_os = "freebsd")] pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> { let ret = unsafe { libc::mkfifo(CString::new(path)?.as_ptr(), mode.try_into()?) }; @@ -60,6 +68,7 @@ pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> { } } +/// A wrapper around the libc **mknod** function, for creating Unix device files #[cfg(target_os = "linux")] pub fn mknod(path: &str, mode: u32, major: u32, minor: u32) -> Result<(), Error> { let dev = libc::makedev(major, minor); @@ -71,6 +80,7 @@ pub fn mknod(path: &str, mode: u32, major: u32, minor: u32) -> Result<(), Error> } } +/// A wrapper around the libc **mknod** function, for creating Unix device files #[cfg(target_os = "freebsd")] pub fn mknod(path: &str, mode: u32, major: u32, minor: u32) -> Result<(), Error> { let dev = libc::makedev(major, minor); diff --git a/src/node.rs b/src/node.rs index 044a734..b7debb4 100644 --- a/src/node.rs +++ b/src/node.rs @@ -64,7 +64,7 @@ impl Node { /// > Note: this function reads an already created node. To create a new node /// > from a file, use the `from_path` method. /// # Errors - /// Returns `crate::Error` if io fails or certain other circumstances + /// Returns `crate::Error` if io fails or the archive is incorrectly formatted pub fn read(reader: &mut T) -> Result { let mut len = [0; 2]; reader.read_exact(&mut len)?; @@ -106,7 +106,7 @@ impl Node { /// > representation. To extract the contents of a `Node` and write out the /// > file it represents, use the `extract` method instead. /// # Errors - /// Returns `crate::Error` if io fails or certain other circumstances + /// Returns `crate::Error` if io fails pub fn write(&self, writer: &mut T) -> Result<(), Error> { let len: u16 = self.name.len().try_into()?; writer.write_all(&len.to_le_bytes())?; diff --git a/src/stream.rs b/src/stream.rs index 7d13ada..f9ddb30 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -36,6 +36,8 @@ impl Iterator for Stream { } } +/// A message to be passed from a background thread to a foreground thread when +/// a `Node` extraction has finished #[cfg(feature = "parallel")] #[derive(Debug)] pub enum Message {