/* ----------------------------------------------------------------------- * * * 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 #include #include #include #include #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); }