diff --git a/rpmust/Cargo.toml b/rpmust/Cargo.toml index f895f2b6e2fa28236e993511b34698e49d35fe88..3b4b58d5af010fc7b23c482a7624e81a6d70be16 100644 --- a/rpmust/Cargo.toml +++ b/rpmust/Cargo.toml @@ -17,4 +17,11 @@ enum-display-derive = "0.1" cpio = "0.2" clap = { version = "3.0.14", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } -serde_yaml = "0.8" \ No newline at end of file +serde_yaml = "0.8" +bzip2 = { version = "0.4", features = ["tokio"] } +flate2 = { version = "1.0.22", features = ["tokio"] } +tar = "0.4.38" +xz = { version = "0.1", features = ["tokio"] } +zstd = "0.10.0" +cpio_reader = "0.1.0" +glob = "0.3.0" \ No newline at end of file diff --git a/rpmust/src/main.rs b/rpmust/src/main.rs index f320e4d27ac2e9f518ba85ff8259332688bced48..41107c2c5656614b6491ce91cbaf0380eec33450 100644 --- a/rpmust/src/main.rs +++ b/rpmust/src/main.rs @@ -24,9 +24,18 @@ $ rpmust build ./RPMPackageMetadata.yaml */ use std::io; +use std::fs; use std::io::prelude::*; use std::fs::File; use rpm::*; +use flate2::read::GzDecoder; +use xz::read::{XzEncoder, XzDecoder}; +use tar::Archive; +use bzip2::Compression; +use bzip2::read::{BzEncoder, BzDecoder}; +use zstd::decode_all; +use glob::glob; + extern crate clap; @@ -48,39 +57,214 @@ fn main() -> io::Result<()> { .about("merge the RPMPackageMetadata.yaml and out.cpio to a rpm file") .arg(arg!( ... "The path of RPMPackageMetadata.yaml")) ) + .subcommand( + App::new("clean") + .about("delete the output file") + ) .get_matches(); match matches.subcommand() { Some(("decode", _sub_matches)) => { - /// get the rpm file path + // get the rpm file path let file_address = _sub_matches.value_of("PATH"); let mut file = std::fs::File::open(file_address.unwrap()).expect("should be able to open rpm file"); - /// get size of rpm file - /// in order to caculate the start - /// of cpio + // get size of rpm file + // in order to caculate the start + // of cpio let file_size = file.metadata().unwrap().len(); let mut buf_reader = std::io::BufReader::with_capacity(file_size as usize,file); let rpmmeta = RPMPackageMetadata::parse(&mut buf_reader); let rpm = rpmmeta.unwrap(); - /// output the RPMPackageMetadata.yaml + // output the RPMPackageMetadata.yaml + println!("Generate the yaml file!"); let s = serde_yaml::to_string(&rpm).unwrap(); let mut buffer = File::create("RPMPackageMetadata.yaml").unwrap(); buffer.write_all(s.as_bytes())?; + println!("Yaml file generated"); + + let mut out_file:File; + + // Traverse index entries to find RPMTAG_PAYLOADCOMPRESSOR + // RPMTAG_PAYLOADCOMPRESSOR shows the compress type + for i in 0..rpm.header.index_entries.len() { + if rpm.header.index_entries[i].tag == IndexTag::RPMTAG_PAYLOADCOMPRESSOR { + match &rpm.header.index_entries[i].data { + IndexData::StringTag(s) => { + if s == "xz" || s == "lzma" { + println!("Extract out.cpio.xz from rpm file"); + out_file = File::create("out.cpio.xz")?; + out_file.write_all(buf_reader.fill_buf().unwrap())?; + let tar_xz = File::open("out.cpio.xz")?; + let mut xz_decoder = XzDecoder::new(tar_xz); + let mut buf = Vec::new(); + xz_decoder.read_to_end(&mut buf); + let mut file = File::create("out.cpio")?; + file.write_all(&buf); + } else if s == "gzip" { + println!("Extract out.cpio.gz from rpm file"); + out_file = File::create("out.cpio.gz")?; + out_file.write_all(buf_reader.fill_buf().unwrap())?; + let tar_gz = File::open("out.cpio.gz")?; + let mut gz_decoder = GzDecoder::new(tar_gz); + let mut buf = Vec::new(); + gz_decoder.read_to_end(&mut buf); + let mut file = File::create("out.cpio")?; + file.write_all(&buf); + } else if s == "zstd" { + println!("Extract out.cpio.zst from rpm file"); + out_file = File::create("out.cpio.zst")?; + out_file.write_all(buf_reader.fill_buf().unwrap())?; + let tar_zst = File::open("out.cpio.zst")?; + let mut tar_f = decode_all(tar_zst)?; + let mut file = File::create("out.cpio")?; + file.write_all(&tar_f); + } else if s == "bzip2" { + println!("Extract out.cpio.bz2 from rpm file"); + out_file = File::create("out.cpio.bz2")?; + out_file.write_all(buf_reader.fill_buf().unwrap())?; + let tar_bz2 = File::open("out.cpio.bz2")?; + let mut bz2_decoder = BzDecoder::new(tar_bz2); + let mut buf = Vec::new(); + bz2_decoder.read_to_end(&mut buf); + let mut file = File::create("out.cpio")?; + file.write_all(&buf); + } else { + println!("Extract out.cpio from rpm file"); + out_file = File::create("out.cpio")?; + out_file.write_all(buf_reader.fill_buf().unwrap())?; + } + }, + _ => { + + } + } + } + } + println!("Decompress the out.cpio"); + let cpio = fs::read("out.cpio").unwrap(); - /// output the out.cpio - let mut out_file = File::create("out.cpio")?; - out_file.write_all(buf_reader.fill_buf().unwrap())?; + for entry in cpio_reader::iter_files(&cpio) { + println!("\x1b[93mFile name:\x1b[0m {}",entry.name()); + let mut p = &entry.name()[2..entry.name().len()]; + let p = &("./out/".to_owned() + p); + let path = std::path::Path::new(p); + let prefix = path.parent().unwrap(); + if !prefix.exists() { + std::fs::create_dir_all(prefix).unwrap(); + } + if !prefix.exists() { + let mut f = File::create(p)?; + f.write_all(entry.file()); + } + } } Some(("build", _sub_matches)) => { let yaml_path = _sub_matches.value_of("PATH"); let mut file = std::fs::File::open(yaml_path.unwrap()).unwrap(); let mut yaml_str = String::new(); - file.read_to_string(&mut yaml_str).unwrap(); + file.read_to_string(&mut yaml_str).expect("Input the yaml file path"); let rpm: RPMPackageMetadata = serde_yaml::from_str(&yaml_str).expect("yaml read failed!"); - println!("{:#?}",rpm.signature.index_entries); - println!("{:#?}",rpm.header.index_entries); + + println!("Building the out.rpm"); + let mut file = File::create("out.rpm")?; + rpm.write(&mut file); + + let mut cpio_file = Vec::new(); + for i in 0..rpm.header.index_entries.len() { + if rpm.header.index_entries[i].tag == IndexTag::RPMTAG_PAYLOADCOMPRESSOR { + match &rpm.header.index_entries[i].data { + IndexData::StringTag(s) => { + if s == "xz" || s == "lzma" { + cpio_file = fs::read("out.cpio.xz")?; + } else if s == "gzip" { + cpio_file = fs::read("out.cpio.gz")?; + } else if s == "zstd" { + cpio_file = fs::read("out.cpio.zst")?; + } else if s == "bzip2" { + cpio_file = fs::read("out.cpio.bz2")?; + } else { + cpio_file = fs::read("out.cpio")?; + } + }, + _ => { + + } + } + } + } + file.write_all(&cpio_file); + } + Some(("build", _sub_matches)) => { + let yaml_path = _sub_matches.value_of("PATH"); + let mut file = std::fs::File::open(yaml_path.unwrap()).unwrap(); + let mut yaml_str = String::new(); + file.read_to_string(&mut yaml_str).expect("Input the yaml file path"); + let rpm: RPMPackageMetadata = serde_yaml::from_str(&yaml_str).expect("yaml read failed!"); + + println!("Building the out.rpm"); + let mut file = File::create("out.rpm")?; + rpm.write(&mut file); + + let mut cpio_file = Vec::new(); + for i in 0..rpm.header.index_entries.len() { + if rpm.header.index_entries[i].tag == IndexTag::RPMTAG_PAYLOADCOMPRESSOR { + match &rpm.header.index_entries[i].data { + IndexData::StringTag(s) => { + if s == "xz" || s == "lzma" { + cpio_file = fs::read("out.cpio.xz")?; + } else if s == "gzip" { + cpio_file = fs::read("out.cpio.gz")?; + } else if s == "zstd" { + cpio_file = fs::read("out.cpio.zst")?; + } else if s == "bzip2" { + cpio_file = fs::read("out.cpio.bz2")?; + } else { + cpio_file = fs::read("out.cpio")?; + } + }, + _ => { + + } + } + } + } + file.write_all(&cpio_file); + } + Some(("clean", _sub_matches)) => { + let mut is = true; + let out_dir_path = std::path::Path::new("./out"); + if out_dir_path.exists() { + fs::remove_dir_all("./out"); + println!("\x1b[93mRemoving dir out\x1b[0m"); + is = false; + } + + for path in glob("./*.yaml").unwrap() { + match path { + Ok(path) => { + println!("\x1b[93mRemoving file:\x1b[0m {:?}", path.display()); + std::fs::remove_file(path); + is = false; + }, + Err(e) => println!("{:?}", e) + } + } + + for path in glob("./out*").unwrap() { + match path { + Ok(path) => { + println!("\x1b[93mRemoving file:\x1b[0m {:?}", path.display()); + std::fs::remove_file(path); + is = false; + }, + Err(e) => println!("{:?}", e) + } + } + if is { + println!("nothing removed"); + } } _ => {}, } diff --git a/rpmust/src/rpm/headers/header.rs b/rpmust/src/rpm/headers/header.rs index 006ab24bb38944546a5e1f560050893cd1d1ceb2..8f662b6871ba2bf5fb5427906d427ef89d7a1e93 100644 --- a/rpmust/src/rpm/headers/header.rs +++ b/rpmust/src/rpm/headers/header.rs @@ -112,6 +112,15 @@ where store, }) } + + pub(crate) fn write(&self, out: &mut W) -> Result<(), RPMError> { + self.index_header.write(out)?; + for entry in &self.index_entries { + entry.write_index(out)?; + } + out.write_all(&self.store)?; + Ok(()) + } } #[derive(Debug, PartialEq, Serialize, Deserialize)] pub(crate) struct IndexHeader { @@ -156,6 +165,15 @@ impl IndexHeader { header_size, }) } + + pub(crate) fn write(&self, out: &mut W) -> Result<(), RPMError> { + out.write_all(&self.magic)?; + out.write_all(&self.version.to_be_bytes())?; + out.write_all(&[0; 4])?; + out.write_all(&self.num_entries.to_be_bytes())?; + out.write_all(&self.header_size.to_be_bytes())?; + Ok(()) + } } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -202,6 +220,15 @@ impl IndexEnt }, )) } + + pub(crate) fn write_index(&self, out: &mut W) -> Result<(), RPMError> { + let mut written = out.write(&self.tag.to_u32().unwrap().to_be_bytes())?; + written += out.write(&self.data.to_u32().to_be_bytes())?; + written += out.write(&self.offset.to_be_bytes())?; + written += out.write(&self.num_items.to_be_bytes())?; + assert_eq!(16, written, "there should be 16 bytes written"); + Ok(()) + } } impl Header { @@ -219,6 +246,16 @@ impl Header { } Ok(result) } + + pub(crate) fn write_signature(&self, out: &mut W) -> Result<(), RPMError> { + self.write(out)?; + let modulo = self.index_header.header_size % 8; + if modulo > 0 { + let expansion = vec![0; 8 - modulo as usize]; + out.write_all(&expansion)?; + } + Ok(()) + } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] diff --git a/rpmust/src/rpm/headers/lead.rs b/rpmust/src/rpm/headers/lead.rs index 6a656dfd31978d37f77215a52cfe819f6e444af1..833c24fc3647d290d3d2af33691f6aa5e4909b0b 100644 --- a/rpmust/src/rpm/headers/lead.rs +++ b/rpmust/src/rpm/headers/lead.rs @@ -102,6 +102,19 @@ impl Lead { reserved: rest.try_into().unwrap(), }) } + + pub(crate) fn write(&self, out: &mut W) -> Result<(), RPMError> { + out.write_all(&self.magic)?; + out.write_all(&self.major.to_be_bytes())?; + out.write_all(&self.minor.to_be_bytes())?; + out.write_all(&self.package_type.to_be_bytes())?; + out.write_all(&self.arch.to_be_bytes())?; + out.write_all(&self.name)?; + out.write_all(&self.os.to_be_bytes())?; + out.write_all(&self.signature_type.to_be_bytes())?; + out.write_all(&self.reserved)?; + Ok(()) + } } /// impl the serialize and deserialize for [T; 66] diff --git a/rpmust/src/rpm/rpmmeta.rs b/rpmust/src/rpm/rpmmeta.rs index e186f24735ae89db0571e931df071af2ee0d44cc..1234c44c56c860d5f1e4c09d46993635826985dd 100644 --- a/rpmust/src/rpm/rpmmeta.rs +++ b/rpmust/src/rpm/rpmmeta.rs @@ -20,4 +20,11 @@ impl RPMPackageMetadata { header, }) } + + pub(crate) fn write(&self, out: &mut W) -> Result<(), RPMError> { + self.lead.write(out)?; + self.signature.write_signature(out)?; + self.header.write(out)?; + Ok(()) + } } \ No newline at end of file diff --git a/rpmust/src/test/389-ds-base-devel-1.3.8.4-15.el7.x86_64.rpm b/rpmust/src/test/389-ds-base-devel-1.3.8.4-15.el7.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..20cea342b005f0e42044f87c187340379068eafe Binary files /dev/null and b/rpmust/src/test/389-ds-base-devel-1.3.8.4-15.el7.x86_64.rpm differ diff --git a/rpmust/src/test/BackupPC-4.4.0-6.fc36.x86_64.rpm b/rpmust/src/test/BackupPC-4.4.0-6.fc36.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..3b0ee17364aed87459e1e6ecfaf36c5e1328e7ec Binary files /dev/null and b/rpmust/src/test/BackupPC-4.4.0-6.fc36.x86_64.rpm differ diff --git a/rpmust/src/test/SDL-1.2.14-7.el6_7.1.i686.rpm b/rpmust/src/test/SDL-1.2.14-7.el6_7.1.i686.rpm new file mode 100644 index 0000000000000000000000000000000000000000..9bcc135f80d1ae93c9db95ecaa578daf2553bb0c Binary files /dev/null and b/rpmust/src/test/SDL-1.2.14-7.el6_7.1.i686.rpm differ diff --git a/rpmust/src/test/bzip2-1.0.6-lp150.4.6.1.x86_64.rpm b/rpmust/src/test/bzip2-1.0.6-lp150.4.6.1.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..7d6638e007a4e2b65f49e23a26806c100640b61f Binary files /dev/null and b/rpmust/src/test/bzip2-1.0.6-lp150.4.6.1.x86_64.rpm differ diff --git a/rpmust/src/test/bzip2-1.0.8-150400.1.77.aarch64.rpm b/rpmust/src/test/bzip2-1.0.8-150400.1.77.aarch64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..2e0eba0522cd1e2d78ae64943472e568eba4c7d4 Binary files /dev/null and b/rpmust/src/test/bzip2-1.0.8-150400.1.77.aarch64.rpm differ diff --git a/rpmust/src/test/bzip2-1.0.8-2.fc32.ppc64le.rpm b/rpmust/src/test/bzip2-1.0.8-2.fc32.ppc64le.rpm new file mode 100644 index 0000000000000000000000000000000000000000..26091e2a6f818b26e1d336af635b074e5377df9c Binary files /dev/null and b/rpmust/src/test/bzip2-1.0.8-2.fc32.ppc64le.rpm differ diff --git a/rpmust/src/test/bzip2-1.0.8-2.fc32.s390x.rpm b/rpmust/src/test/bzip2-1.0.8-2.fc32.s390x.rpm new file mode 100644 index 0000000000000000000000000000000000000000..0940cc1e96f52641d986d9da706a15ac4c828cef Binary files /dev/null and b/rpmust/src/test/bzip2-1.0.8-2.fc32.s390x.rpm differ diff --git a/rpmust/src/test/bzip2-1.0.8-2.fc32.x86_64.rpm b/rpmust/src/test/bzip2-1.0.8-2.fc32.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..e86db928b7445e3c85190ed45c8841f830c7f79b Binary files /dev/null and b/rpmust/src/test/bzip2-1.0.8-2.fc32.x86_64.rpm differ diff --git a/rpmust/src/test/bzip2-1.0.8-2.mga8.i586.rpm b/rpmust/src/test/bzip2-1.0.8-2.mga8.i586.rpm new file mode 100644 index 0000000000000000000000000000000000000000..1a9c3fd7b0dbad9b7eddf3d020cfee8c5d8f648b Binary files /dev/null and b/rpmust/src/test/bzip2-1.0.8-2.mga8.i586.rpm differ diff --git a/rpmust/src/test/bzip2-1.0.8-9.fc35.armv7hl.rpm b/rpmust/src/test/bzip2-1.0.8-9.fc35.armv7hl.rpm new file mode 100644 index 0000000000000000000000000000000000000000..3538b4ff4c228baaffda172823b9400d9be1a0aa Binary files /dev/null and b/rpmust/src/test/bzip2-1.0.8-9.fc35.armv7hl.rpm differ diff --git a/rpmust/src/test/centos-release-samba412-1.0-1.el8.noarch.rpm b/rpmust/src/test/centos-release-samba412-1.0-1.el8.noarch.rpm new file mode 100644 index 0000000000000000000000000000000000000000..1354043ec04b914d36fbb0e18bfacc23c2070e75 Binary files /dev/null and b/rpmust/src/test/centos-release-samba412-1.0-1.el8.noarch.rpm differ diff --git a/rpmust/src/test/clang-10.0.1-0.oe1.aarch64.rpm b/rpmust/src/test/clang-10.0.1-0.oe1.aarch64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..535c197140c2c55a67691a5b1968a7d1eb8e5678 Binary files /dev/null and b/rpmust/src/test/clang-10.0.1-0.oe1.aarch64.rpm differ diff --git a/rpmust/src/test/eclipse-nls-id-3.6.0.v20120721114722-2.el6.x86_64.rpm b/rpmust/src/test/eclipse-nls-id-3.6.0.v20120721114722-2.el6.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..f1fb9c9c237796fde08fc6aa98cb0c928e801e4e Binary files /dev/null and b/rpmust/src/test/eclipse-nls-id-3.6.0.v20120721114722-2.el6.x86_64.rpm differ diff --git a/rpmust/src/test/git-daemon-1.7.1-8.el6.x86_64.rpm b/rpmust/src/test/git-daemon-1.7.1-8.el6.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..439618670c2d567343a4b0e161aa8b3de96f52f7 Binary files /dev/null and b/rpmust/src/test/git-daemon-1.7.1-8.el6.x86_64.rpm differ diff --git a/rpmust/src/test/glibc-common-2.12-1.209.el6.x86_64.rpm b/rpmust/src/test/glibc-common-2.12-1.209.el6.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..c3c190305e93f5eab5d9afd1ce813d6f19974202 Binary files /dev/null and b/rpmust/src/test/glibc-common-2.12-1.209.el6.x86_64.rpm differ diff --git a/rpmust/src/test/ima_signed.rpm b/rpmust/src/test/ima_signed.rpm new file mode 100644 index 0000000000000000000000000000000000000000..a5c844324943f6e19a24b2b574467d9236d005c4 Binary files /dev/null and b/rpmust/src/test/ima_signed.rpm differ diff --git a/rpmust/src/test/jikes-1.23-0.20050308.14-omv4050.x86_64.rpm b/rpmust/src/test/jikes-1.23-0.20050308.14-omv4050.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..876c0d344f72af5cbfa144bb11de69a57457af82 Binary files /dev/null and b/rpmust/src/test/jikes-1.23-0.20050308.14-omv4050.x86_64.rpm differ diff --git a/rpmust/src/test/libucil-0.9.10-7.el7.aarch64.rpm b/rpmust/src/test/libucil-0.9.10-7.el7.aarch64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..6383167e4a39ca2d8887dbc1e2a27a339f80d284 Binary files /dev/null and b/rpmust/src/test/libucil-0.9.10-7.el7.aarch64.rpm differ diff --git a/rpmust/src/test/llvm-10.0.1-2.oe1.aarch64.rpm b/rpmust/src/test/llvm-10.0.1-2.oe1.aarch64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..7433ea46410f4dd8d3b04df9a769377646e5b8a4 Binary files /dev/null and b/rpmust/src/test/llvm-10.0.1-2.oe1.aarch64.rpm differ diff --git a/rpmust/src/test/monkeysphere-0.37-1.el7.noarch.rpm b/rpmust/src/test/monkeysphere-0.37-1.el7.noarch.rpm new file mode 100644 index 0000000000000000000000000000000000000000..6889c54f2590192f57b6ba555f48a69683efe3c1 Binary files /dev/null and b/rpmust/src/test/monkeysphere-0.37-1.el7.noarch.rpm differ diff --git a/rpmust/src/test/qemu-4.1.0-13.oe1.x86_64.rpm b/rpmust/src/test/qemu-4.1.0-13.oe1.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..83eea625f4872920b5789bb81f48f77b1a5ddc89 Binary files /dev/null and b/rpmust/src/test/qemu-4.1.0-13.oe1.x86_64.rpm differ diff --git a/rpmust/src/test/qt-mysql-4.8.7-67.fc36.i686.rpm b/rpmust/src/test/qt-mysql-4.8.7-67.fc36.i686.rpm new file mode 100644 index 0000000000000000000000000000000000000000..83ee13e11784165f4644a4f495fd3b6ebab584ba Binary files /dev/null and b/rpmust/src/test/qt-mysql-4.8.7-67.fc36.i686.rpm differ diff --git a/rpmust/src/test/rpm-sign-4.15.1-1.fc31.x86_64.rpm b/rpmust/src/test/rpm-sign-4.15.1-1.fc31.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..eeae84b67f9d9a4d4b403086d224402b1f0658c8 Binary files /dev/null and b/rpmust/src/test/rpm-sign-4.15.1-1.fc31.x86_64.rpm differ