From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 322A26CE3D for ; Wed, 31 Mar 2021 12:22:32 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id C5F7BDF2A for ; Wed, 31 Mar 2021 12:22:31 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [212.186.127.180]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id C8992DE6C for ; Wed, 31 Mar 2021 12:22:26 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 997C145959 for ; Wed, 31 Mar 2021 12:22:26 +0200 (CEST) From: Stefan Reiter To: pbs-devel@lists.proxmox.com Date: Wed, 31 Mar 2021 12:21:55 +0200 Message-Id: <20210331102202.14767-14-s.reiter@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210331102202.14767-1-s.reiter@proxmox.com> References: <20210331102202.14767-1-s.reiter@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.019 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [tools.rs, cpio.rs] Subject: [pbs-devel] [PATCH v3 proxmox-backup 13/20] add tools/cpio encoding module X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 31 Mar 2021 10:22:32 -0000 Signed-off-by: Stefan Reiter --- src/tools.rs | 1 + src/tools/cpio.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/tools/cpio.rs diff --git a/src/tools.rs b/src/tools.rs index 7e3bff7b..43fd070e 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -22,6 +22,7 @@ pub mod apt; pub mod async_io; pub mod borrow; pub mod cert; +pub mod cpio; pub mod daemon; pub mod disks; pub mod format; diff --git a/src/tools/cpio.rs b/src/tools/cpio.rs new file mode 100644 index 00000000..8800e3ad --- /dev/null +++ b/src/tools/cpio.rs @@ -0,0 +1,73 @@ +//! Provides a very basic "newc" format cpio encoder. +//! See 'man 5 cpio' for format details, as well as: +//! https://www.kernel.org/doc/html/latest/driver-api/early-userspace/buffer-format.html +//! This does not provide full support for the format, only what is needed to include files in an +//! initramfs intended for a linux kernel. +use anyhow::{bail, Error}; +use std::ffi::{CString, CStr}; +use tokio::io::{copy, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + +/// Write a cpio file entry to an AsyncWrite. +pub async fn append_file( + mut target: W, + content: R, + name: &CStr, + inode: u16, + mode: u16, + uid: u16, + gid: u16, + // negative mtimes are generally valid, but cpio defines all fields as unsigned + mtime: u64, + // c_filesize has 8 bytes, but man page claims that 4 GB files are the maximum, let's be safe + size: u32, +) -> Result<(), Error> { + let name = name.to_bytes_with_nul(); + + target.write_all(b"070701").await?; // c_magic + print_cpio_hex(&mut target, inode as u64).await?; // c_ino + print_cpio_hex(&mut target, mode as u64).await?; // c_mode + print_cpio_hex(&mut target, uid as u64).await?; // c_uid + print_cpio_hex(&mut target, gid as u64).await?; // c_gid + print_cpio_hex(&mut target, 0).await?; // c_nlink + print_cpio_hex(&mut target, mtime as u64).await?; // c_mtime + print_cpio_hex(&mut target, size as u64).await?; // c_filesize + print_cpio_hex(&mut target, 0).await?; // c_devmajor + print_cpio_hex(&mut target, 0).await?; // c_devminor + print_cpio_hex(&mut target, 0).await?; // c_rdevmajor + print_cpio_hex(&mut target, 0).await?; // c_rdevminor + print_cpio_hex(&mut target, name.len() as u64).await?; // c_namesize + print_cpio_hex(&mut target, 0).await?; // c_check (ignored for newc) + + target.write_all(name).await?; + let header_size = 6 + 8*13 + name.len(); + let mut name_pad = header_size; + while name_pad & 3 != 0 { + target.write_u8(0).await?; + name_pad += 1; + } + + let mut content = content.take(size as u64); + let copied = copy(&mut content, &mut target).await?; + if copied < size as u64 { + bail!("cpio: not enough data, or size to big - encoding invalid"); + } + let mut data_pad = copied; + while data_pad & 3 != 0 { + target.write_u8(0).await?; + data_pad += 1; + } + + Ok(()) +} + +/// Write the TRAILER!!! file to an AsyncWrite, signifying the end of a cpio archive. Note that you +/// can immediately add more files after, to create a concatenated archive, the kernel for example +/// will merge these upon loading an initramfs. +pub async fn append_trailer(target: W) -> Result<(), Error> { + let name = CString::new("TRAILER!!!").unwrap(); + append_file(target, tokio::io::empty(), &name, 0, 0, 0, 0, 0, 0).await +} + +async fn print_cpio_hex(target: &mut W, value: u64) -> Result<(), Error> { + target.write_all(format!("{:08x}", value).as_bytes()).await.map_err(|e| e.into()) +} -- 2.20.1