diff options
Diffstat (limited to 'contrib/syslinux-4.02/com32/lib/syslinux/initramfs_file.c')
-rw-r--r-- | contrib/syslinux-4.02/com32/lib/syslinux/initramfs_file.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/com32/lib/syslinux/initramfs_file.c b/contrib/syslinux-4.02/com32/lib/syslinux/initramfs_file.c new file mode 100644 index 0000000..763eff2 --- /dev/null +++ b/contrib/syslinux-4.02/com32/lib/syslinux/initramfs_file.c @@ -0,0 +1,161 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * initramfs_file.c + * + * Utility functions to add arbitrary files including cpio header + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <syslinux/linux.h> + +#define CPIO_MAGIC "070701" +struct cpio_header { + char c_magic[6]; /* 070701 */ + char c_ino[8]; /* Inode number */ + char c_mode[8]; /* File mode and permissions */ + char c_uid[8]; /* uid */ + char c_gid[8]; /* gid */ + char c_nlink[8]; /* Number of links */ + char c_mtime[8]; /* Modification time */ + char c_filesize[8]; /* Size of data field */ + char c_maj[8]; /* File device major number */ + char c_min[8]; /* File device minor number */ + char c_rmaj[8]; /* Device node reference major number */ + char c_rmin[8]; /* Device node reference minor number */ + char c_namesize[8]; /* Length of filename including final \0 */ + char c_chksum[8]; /* Checksum if c_magic ends in 2 */ +}; + +static uint32_t next_ino = 1; + +/* Create cpio headers for the directory entries leading up to a file. + Returns the number of bytes; doesn't touch the buffer if too small. */ +static size_t initramfs_mkdirs(const char *filename, void *buffer, + size_t buflen) +{ + const char *p = filename; + char *bp = buffer; + int len; + size_t bytes = 0; + int pad; + + while ((p = strchr(p, '/'))) { + if (p != filename && p[-1] != '/') { + len = p - filename; + bytes += ((sizeof(struct cpio_header) + len + 1) + 3) & ~3; + } + p++; + } + + if (buflen >= bytes) { + p = filename; + while ((p = strchr(p, '/'))) { + if (p != filename && p[-1] != '/') { + len = p - filename; + bp += sprintf(bp, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x" + "%08x%08x%08x%08x", next_ino++, S_IFDIR | 0755, + 0, 0, 1, 0, 0, 0, 1, 0, 1, len + 1, 0); + memcpy(bp, filename, len); + bp += len; + pad = (-(sizeof(struct cpio_header) + len) & 3) + 1; + memset(bp, 0, pad); + bp += pad; + } + } + } + + return bytes; +} + +/* + * Create a file header (with optional parent directory entries) + * and add it to an initramfs chain + */ +int initramfs_mknod(struct initramfs *ihead, const char *filename, + int do_mkdir, + uint16_t mode, size_t len, uint32_t major, uint32_t minor) +{ + size_t bytes; + int namelen = strlen(filename); + int pad; + char *buffer, *bp; + + if (do_mkdir) + bytes = initramfs_mkdirs(filename, NULL, 0); + else + bytes = 0; + + bytes += ((sizeof(struct cpio_header) + namelen + 1) + 3) & ~3; + + bp = buffer = malloc(bytes); + if (!buffer) + return -1; + + if (do_mkdir) + bp += initramfs_mkdirs(filename, bp, bytes); + + bp += sprintf(bp, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x" + "%08x%08x%08x%08x", next_ino++, mode, + 0, 0, 1, 0, len, 0, 1, major, minor, namelen + 1, 0); + memcpy(bp, filename, namelen); + bp += len; + pad = (-(sizeof(struct cpio_header) + namelen) & 3) + 1; + memset(bp, 0, pad); + + if (initramfs_add_data(ihead, buffer, bytes, bytes, 4)) { + free(buffer); + return -1; + } + + return 0; +} + +/* + * Add a file given data in memory to an initramfs chain. This + * can be used to create nonfiles like symlinks by specifying an + * appropriate mode. + */ +int initramfs_add_file(struct initramfs *ihead, const void *data, + size_t data_len, size_t len, + const char *filename, int do_mkdir, uint32_t mode) +{ + if (initramfs_mknod(ihead, filename, do_mkdir, + (mode & S_IFMT) ? mode : mode | S_IFREG, len, 0, 1)) + return -1; + + return initramfs_add_data(ihead, data, data_len, len, 4); +} + +int initramfs_add_trailer(struct initramfs *ihead) +{ + return initramfs_mknod(ihead, "TRAILER!!!", 0, 0, 0, 0, 0); +} |