1e6459606SH. Peter Anvin /* ----------------------------------------------------------------------- * 2e6459606SH. Peter Anvin * 3e6459606SH. Peter Anvin * Copyright 2012 Intel Corporation; author H. Peter Anvin 4e6459606SH. Peter Anvin * 5e6459606SH. Peter Anvin * This file is part of the Linux kernel, and is made available 6e6459606SH. Peter Anvin * under the terms of the GNU General Public License version 2, as 7e6459606SH. Peter Anvin * published by the Free Software Foundation. 8e6459606SH. Peter Anvin * 9e6459606SH. Peter Anvin * This program is distributed in the hope it will be useful, but 10e6459606SH. Peter Anvin * WITHOUT ANY WARRANTY; without even the implied warranty of 11e6459606SH. Peter Anvin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12e6459606SH. Peter Anvin * General Public License for more details. 13e6459606SH. Peter Anvin * 14e6459606SH. Peter Anvin * ----------------------------------------------------------------------- */ 15e6459606SH. Peter Anvin 16e6459606SH. Peter Anvin /* 17e6459606SH. Peter Anvin * earlycpio.c 18e6459606SH. Peter Anvin * 19e6459606SH. Peter Anvin * Find a specific cpio member; must precede any compressed content. 20e6459606SH. Peter Anvin * This is used to locate data items in the initramfs used by the 21e6459606SH. Peter Anvin * kernel itself during early boot (before the main initramfs is 22e6459606SH. Peter Anvin * decompressed.) It is the responsibility of the initramfs creator 23e6459606SH. Peter Anvin * to ensure that these items are uncompressed at the head of the 24e6459606SH. Peter Anvin * blob. Depending on the boot loader or package tool that may be a 25e6459606SH. Peter Anvin * separate file or part of the same file. 26e6459606SH. Peter Anvin */ 27e6459606SH. Peter Anvin 28e6459606SH. Peter Anvin #include <linux/earlycpio.h> 29e6459606SH. Peter Anvin #include <linux/kernel.h> 30e6459606SH. Peter Anvin #include <linux/string.h> 31e6459606SH. Peter Anvin 32e6459606SH. Peter Anvin enum cpio_fields { 33e6459606SH. Peter Anvin C_MAGIC, 34e6459606SH. Peter Anvin C_INO, 35e6459606SH. Peter Anvin C_MODE, 36e6459606SH. Peter Anvin C_UID, 37e6459606SH. Peter Anvin C_GID, 38e6459606SH. Peter Anvin C_NLINK, 39e6459606SH. Peter Anvin C_MTIME, 40e6459606SH. Peter Anvin C_FILESIZE, 41e6459606SH. Peter Anvin C_MAJ, 42e6459606SH. Peter Anvin C_MIN, 43e6459606SH. Peter Anvin C_RMAJ, 44e6459606SH. Peter Anvin C_RMIN, 45e6459606SH. Peter Anvin C_NAMESIZE, 46e6459606SH. Peter Anvin C_CHKSUM, 47e6459606SH. Peter Anvin C_NFIELDS 48e6459606SH. Peter Anvin }; 49e6459606SH. Peter Anvin 50e6459606SH. Peter Anvin /** 51e6459606SH. Peter Anvin * cpio_data find_cpio_data - Search for files in an uncompressed cpio 52e6459606SH. Peter Anvin * @path: The directory to search for, including a slash at the end 53e6459606SH. Peter Anvin * @data: Pointer to the the cpio archive or a header inside 54e6459606SH. Peter Anvin * @len: Remaining length of the cpio based on data pointer 55*598bae70STang Chen * @nextoff: When a matching file is found, this is the offset from the 56*598bae70STang Chen * beginning of the cpio to the beginning of the next file, not the 57*598bae70STang Chen * matching file itself. It can be used to iterate through the cpio 58*598bae70STang Chen * to find all files inside of a directory path. 59e6459606SH. Peter Anvin * 60e6459606SH. Peter Anvin * @return: struct cpio_data containing the address, length and 61e6459606SH. Peter Anvin * filename (with the directory path cut off) of the found file. 62e6459606SH. Peter Anvin * If you search for a filename and not for files in a directory, 63e6459606SH. Peter Anvin * pass the absolute path of the filename in the cpio and make sure 64e6459606SH. Peter Anvin * the match returned an empty filename string. 65e6459606SH. Peter Anvin */ 66e6459606SH. Peter Anvin 670db0628dSPaul Gortmaker struct cpio_data find_cpio_data(const char *path, void *data, 68*598bae70STang Chen size_t len, long *nextoff) 69e6459606SH. Peter Anvin { 70e6459606SH. Peter Anvin const size_t cpio_header_len = 8*C_NFIELDS - 2; 71e6459606SH. Peter Anvin struct cpio_data cd = { NULL, 0, "" }; 72e6459606SH. Peter Anvin const char *p, *dptr, *nptr; 73e6459606SH. Peter Anvin unsigned int ch[C_NFIELDS], *chp, v; 74e6459606SH. Peter Anvin unsigned char c, x; 75e6459606SH. Peter Anvin size_t mypathsize = strlen(path); 76e6459606SH. Peter Anvin int i, j; 77e6459606SH. Peter Anvin 78e6459606SH. Peter Anvin p = data; 79e6459606SH. Peter Anvin 80e6459606SH. Peter Anvin while (len > cpio_header_len) { 81e6459606SH. Peter Anvin if (!*p) { 82e6459606SH. Peter Anvin /* All cpio headers need to be 4-byte aligned */ 83e6459606SH. Peter Anvin p += 4; 84e6459606SH. Peter Anvin len -= 4; 85e6459606SH. Peter Anvin continue; 86e6459606SH. Peter Anvin } 87e6459606SH. Peter Anvin 88e6459606SH. Peter Anvin j = 6; /* The magic field is only 6 characters */ 89e6459606SH. Peter Anvin chp = ch; 90e6459606SH. Peter Anvin for (i = C_NFIELDS; i; i--) { 91e6459606SH. Peter Anvin v = 0; 92e6459606SH. Peter Anvin while (j--) { 93e6459606SH. Peter Anvin v <<= 4; 94e6459606SH. Peter Anvin c = *p++; 95e6459606SH. Peter Anvin 96e6459606SH. Peter Anvin x = c - '0'; 97e6459606SH. Peter Anvin if (x < 10) { 98e6459606SH. Peter Anvin v += x; 99e6459606SH. Peter Anvin continue; 100e6459606SH. Peter Anvin } 101e6459606SH. Peter Anvin 102e6459606SH. Peter Anvin x = (c | 0x20) - 'a'; 103e6459606SH. Peter Anvin if (x < 6) { 104e6459606SH. Peter Anvin v += x + 10; 105e6459606SH. Peter Anvin continue; 106e6459606SH. Peter Anvin } 107e6459606SH. Peter Anvin 108e6459606SH. Peter Anvin goto quit; /* Invalid hexadecimal */ 109e6459606SH. Peter Anvin } 110e6459606SH. Peter Anvin *chp++ = v; 111e6459606SH. Peter Anvin j = 8; /* All other fields are 8 characters */ 112e6459606SH. Peter Anvin } 113e6459606SH. Peter Anvin 114e6459606SH. Peter Anvin if ((ch[C_MAGIC] - 0x070701) > 1) 115e6459606SH. Peter Anvin goto quit; /* Invalid magic */ 116e6459606SH. Peter Anvin 117e6459606SH. Peter Anvin len -= cpio_header_len; 118e6459606SH. Peter Anvin 119e6459606SH. Peter Anvin dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4); 120e6459606SH. Peter Anvin nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4); 121e6459606SH. Peter Anvin 122e6459606SH. Peter Anvin if (nptr > p + len || dptr < p || nptr < dptr) 123e6459606SH. Peter Anvin goto quit; /* Buffer overrun */ 124e6459606SH. Peter Anvin 125e6459606SH. Peter Anvin if ((ch[C_MODE] & 0170000) == 0100000 && 126e6459606SH. Peter Anvin ch[C_NAMESIZE] >= mypathsize && 127e6459606SH. Peter Anvin !memcmp(p, path, mypathsize)) { 128*598bae70STang Chen *nextoff = (long)nptr - (long)data; 129e6459606SH. Peter Anvin if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { 130e6459606SH. Peter Anvin pr_warn( 131e6459606SH. Peter Anvin "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", 132e6459606SH. Peter Anvin p, MAX_CPIO_FILE_NAME); 133e6459606SH. Peter Anvin } 134e6459606SH. Peter Anvin strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME); 135e6459606SH. Peter Anvin 136e6459606SH. Peter Anvin cd.data = (void *)dptr; 137e6459606SH. Peter Anvin cd.size = ch[C_FILESIZE]; 138e6459606SH. Peter Anvin return cd; /* Found it! */ 139e6459606SH. Peter Anvin } 140e6459606SH. Peter Anvin len -= (nptr - p); 141e6459606SH. Peter Anvin p = nptr; 142e6459606SH. Peter Anvin } 143e6459606SH. Peter Anvin 144e6459606SH. Peter Anvin quit: 145e6459606SH. Peter Anvin return cd; 146e6459606SH. Peter Anvin } 147