mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.6 KiB
141 lines
3.6 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* ----------------------------------------------------------------------- * |
|
* |
|
* Copyright 2012 Intel Corporation; author H. Peter Anvin |
|
* |
|
* ----------------------------------------------------------------------- */ |
|
|
|
/* |
|
* earlycpio.c |
|
* |
|
* Find a specific cpio member; must precede any compressed content. |
|
* This is used to locate data items in the initramfs used by the |
|
* kernel itself during early boot (before the main initramfs is |
|
* decompressed.) It is the responsibility of the initramfs creator |
|
* to ensure that these items are uncompressed at the head of the |
|
* blob. Depending on the boot loader or package tool that may be a |
|
* separate file or part of the same file. |
|
*/ |
|
|
|
#include <linux/earlycpio.h> |
|
#include <linux/kernel.h> |
|
#include <linux/string.h> |
|
|
|
enum cpio_fields { |
|
C_MAGIC, |
|
C_INO, |
|
C_MODE, |
|
C_UID, |
|
C_GID, |
|
C_NLINK, |
|
C_MTIME, |
|
C_FILESIZE, |
|
C_MAJ, |
|
C_MIN, |
|
C_RMAJ, |
|
C_RMIN, |
|
C_NAMESIZE, |
|
C_CHKSUM, |
|
C_NFIELDS |
|
}; |
|
|
|
/** |
|
* find_cpio_data - Search for files in an uncompressed cpio |
|
* @path: The directory to search for, including a slash at the end |
|
* @data: Pointer to the cpio archive or a header inside |
|
* @len: Remaining length of the cpio based on data pointer |
|
* @nextoff: When a matching file is found, this is the offset from the |
|
* beginning of the cpio to the beginning of the next file, not the |
|
* matching file itself. It can be used to iterate through the cpio |
|
* to find all files inside of a directory path. |
|
* |
|
* Return: &struct cpio_data containing the address, length and |
|
* filename (with the directory path cut off) of the found file. |
|
* If you search for a filename and not for files in a directory, |
|
* pass the absolute path of the filename in the cpio and make sure |
|
* the match returned an empty filename string. |
|
*/ |
|
|
|
struct cpio_data find_cpio_data(const char *path, void *data, |
|
size_t len, long *nextoff) |
|
{ |
|
const size_t cpio_header_len = 8*C_NFIELDS - 2; |
|
struct cpio_data cd = { NULL, 0, "" }; |
|
const char *p, *dptr, *nptr; |
|
unsigned int ch[C_NFIELDS], *chp, v; |
|
unsigned char c, x; |
|
size_t mypathsize = strlen(path); |
|
int i, j; |
|
|
|
p = data; |
|
|
|
while (len > cpio_header_len) { |
|
if (!*p) { |
|
/* All cpio headers need to be 4-byte aligned */ |
|
p += 4; |
|
len -= 4; |
|
continue; |
|
} |
|
|
|
j = 6; /* The magic field is only 6 characters */ |
|
chp = ch; |
|
for (i = C_NFIELDS; i; i--) { |
|
v = 0; |
|
while (j--) { |
|
v <<= 4; |
|
c = *p++; |
|
|
|
x = c - '0'; |
|
if (x < 10) { |
|
v += x; |
|
continue; |
|
} |
|
|
|
x = (c | 0x20) - 'a'; |
|
if (x < 6) { |
|
v += x + 10; |
|
continue; |
|
} |
|
|
|
goto quit; /* Invalid hexadecimal */ |
|
} |
|
*chp++ = v; |
|
j = 8; /* All other fields are 8 characters */ |
|
} |
|
|
|
if ((ch[C_MAGIC] - 0x070701) > 1) |
|
goto quit; /* Invalid magic */ |
|
|
|
len -= cpio_header_len; |
|
|
|
dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4); |
|
nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4); |
|
|
|
if (nptr > p + len || dptr < p || nptr < dptr) |
|
goto quit; /* Buffer overrun */ |
|
|
|
if ((ch[C_MODE] & 0170000) == 0100000 && |
|
ch[C_NAMESIZE] >= mypathsize && |
|
!memcmp(p, path, mypathsize)) { |
|
|
|
if (nextoff) |
|
*nextoff = (long)nptr - (long)data; |
|
|
|
if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { |
|
pr_warn( |
|
"File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", |
|
p, MAX_CPIO_FILE_NAME); |
|
} |
|
strscpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME); |
|
|
|
cd.data = (void *)dptr; |
|
cd.size = ch[C_FILESIZE]; |
|
return cd; /* Found it! */ |
|
} |
|
len -= (nptr - p); |
|
p = nptr; |
|
} |
|
|
|
quit: |
|
return cd; |
|
}
|
|
|