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