[cpio] Allow for construction of parent directories as needed

iPXE allows individual raw files to be automatically wrapped with
suitable CPIO headers and injected into the magic initrd image as
exposed to a booted Linux kernel.  This feature is currently limited
to placing files within directories that already exist in the initrd
filesystem.

Remove this limitation by adding the ability for iPXE to construct
CPIO headers for parent directories as needed, under control of the
"mkdir=<n>" command-line argument.  For example:

  initrd config.ign /usr/share/oem/config.ign mkdir=1

will create CPIO headers for the "/usr/share/oem" directory as well as
for the "/usr/share/oem/config.ign" file itself.

This simplifies the process of booting operating systems such as
Flatcar Linux, which otherwise require the single "config.ign" file to
be manually wrapped up as a CPIO archive solely in order to create the
relevant parent directory entries.

The value <n> may be used to control the number of parent directory
entries that are created.  For example, "mkdir=2" would cause up to
two parent directories to be created (i.e. "/usr/share" and
"/usr/share/oem" in the above example).  A negative value such as
"mkdir=-1" may be used to create all parent directories up to the root
of the tree.

Do not create any parent directory entries by default, since doing so
would potentially cause the modes and ownership information for
existing directories to be overwritten.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-02-24 14:04:06 +00:00
parent e7595fe88d
commit 12ea8c4074
4 changed files with 161 additions and 52 deletions

View File

@@ -245,6 +245,7 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
size_t cpio_len;
size_t name_len;
size_t len;
unsigned int i;
/* Read from file */
len = 0;
@@ -263,15 +264,16 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
}
len += efi_file_read_chunk ( reader, UNULL, pad_len );
/* Read CPIO header, if applicable */
cpio_len = cpio_header ( image, &cpio );
if ( cpio_len ) {
name = cpio_name ( image );
name_len = cpio_name_len ( image );
pad_len = ( cpio_len - sizeof ( cpio ) - name_len );
/* Read CPIO header(s), if applicable */
name = cpio_name ( image );
for ( i = 0 ; ( cpio_len = cpio_header ( image, i, &cpio ) );
i++ ) {
name_len = ( cpio_len - sizeof ( cpio ) );
pad_len = cpio_pad_len ( cpio_len );
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s header\n",
efi_file_name ( file ), reader->pos,
( reader->pos + cpio_len ), image->name );
( reader->pos + cpio_len + pad_len ),
image->name );
len += efi_file_read_chunk ( reader,
virt_to_user ( &cpio ),
sizeof ( cpio ) );