summaryrefslogtreecommitdiff
path: root/precompiled.c
diff options
context:
space:
mode:
Diffstat (limited to 'precompiled.c')
-rw-r--r--precompiled.c826
1 files changed, 689 insertions, 137 deletions
diff --git a/precompiled.c b/precompiled.c
index ae1ab91..a5f8bfc 100644
--- a/precompiled.c
+++ b/precompiled.c
@@ -19,10 +19,6 @@
*
* precompiled.c - this source file contains functions for dealing
* with precompiled kernel interfaces.
- *
- * XXX portions of these functions are lifted from mkprecompiled (it
- * was much easier to duplicate them than to finesse the code to be
- * shared between the installer and mkprecompiled).
*/
@@ -42,32 +38,37 @@
#include "misc.h"
#include "crc.h"
-#define PRECOMPILED_CONSTANT_LENGTH (8 + 4 + 4 + 4 + 4)
+
+
+static int precompiled_read_fileinfo(Options *op, PrecompiledFileInfo *fileInfos,
+ int index, char *buf, int offset, int size);
/*
- * decode_uint32() - given an index into a buffer, read the next 4
- * bytes, and build a uint32.
+ * read_uint32() - given a buffer and an offset, read the next 4 bytes from
+ * the buffer at the given offset, build a uint32, and advance the offset.
*/
-static uint32 decode_uint32(char *buf)
+static uint32 read_uint32(const char *buf, int *offset)
{
uint32 ret = 0;
- ret += (((uint32) buf[3]) & 0xff);
+ ret += (((uint32) buf[*offset + 3]) & 0xff);
ret <<= 8;
- ret += (((uint32) buf[2]) & 0xff);
+ ret += (((uint32) buf[*offset + 2]) & 0xff);
ret <<= 8;
- ret += (((uint32) buf[1]) & 0xff);
+ ret += (((uint32) buf[*offset + 1]) & 0xff);
ret <<= 8;
- ret += (((uint32) buf[0]) & 0xff);
+ ret += (((uint32) buf[*offset]) & 0xff);
ret <<= 0;
+ *offset += sizeof(uint32);
+
return ret;
-} /* decode_uint32() */
+}
@@ -78,15 +79,15 @@ static uint32 decode_uint32(char *buf)
* mounted.
*/
-char *read_proc_version(Options *op)
+char *read_proc_version(Options *op, const char *proc_mount_point)
{
int fd, ret, len, version_len;
char *version, *c = NULL;
char *proc_verson_filename;
- len = strlen(op->proc_mount_point) + 9; /* strlen("/version") + 1 */
+ len = strlen(proc_mount_point) + 9; /* strlen("/version") + 1 */
proc_verson_filename = (char *) nvalloc(len);
- snprintf(proc_verson_filename, len, "%s/version", op->proc_mount_point);
+ snprintf(proc_verson_filename, len, "%s/version", proc_mount_point);
if ((fd = open(proc_verson_filename, O_RDONLY)) == -1) {
ui_warn(op, "Unable to open the file '%s' (%s).",
@@ -139,27 +140,26 @@ char *read_proc_version(Options *op)
/*
- * precompiled_unpack() - unpack the specified package. It's not
- * really an error if we can't open the file or if it's not the right
- * format, so just throw an expert-only log message.
+ * get_precompiled_info() - load the the specified package into a
+ * PrecompiledInfo record. It's not really an error if we can't open the file
+ * or if it's not the right format, so just throw an expert-only log message.
*/
-PrecompiledInfo *precompiled_unpack(Options *op,
- const char *filename,
- const char *output_filename,
- const char *real_proc_version_string,
- const char *package_version)
+PrecompiledInfo *get_precompiled_info(Options *op,
+ const char *filename,
+ const char *real_proc_version_string,
+ const char *package_version)
{
- int dst_fd, fd, offset, len = 0;
- char *buf, *dst;
- uint32 crc, val, size, linked_module_crc;
- char *version, *description, *proc_version_string,
- *detached_signature = NULL;
+ int fd, offset, num_files, i;
+ char *buf;
+ uint32 val, size;
+ char *version, *description, *proc_version_string;
struct stat stat_buf;
PrecompiledInfo *info = NULL;
+ PrecompiledFileInfo *fileInfos = NULL;
- fd = dst_fd = size = 0;
- buf = dst = description = proc_version_string = NULL;
+ fd = size = 0;
+ buf = description = proc_version_string = NULL;
/* open the file to be unpacked */
@@ -180,7 +180,7 @@ PrecompiledInfo *precompiled_unpack(Options *op,
/* check for a minimum length */
- if (size < PRECOMPILED_CONSTANT_LENGTH) {
+ if (size < PRECOMPILED_PKG_CONSTANT_LENGTH) {
ui_expert(op, "File '%s' appears to be too short.", filename);
goto done;
}
@@ -197,22 +197,25 @@ PrecompiledInfo *precompiled_unpack(Options *op,
/* check for the header */
- if (strncmp(buf + offset, "NVIDIA ", 8) != 0) {
+ if (strncmp(buf + offset, PRECOMPILED_PKG_HEADER, 8) != 0) {
ui_expert(op, "File '%s': unrecognized file format.", filename);
goto done;
}
offset += 8;
- /* read the crc */
+ /* check the package format version */
- crc = decode_uint32(buf + offset);
- offset += 4;
+ val = read_uint32(buf, &offset);
+ if (val != PRECOMPILED_PKG_VERSION) {
+ ui_expert(op, "Incompatible package format version %d: expected %d.",
+ val, PRECOMPILED_PKG_VERSION);
+ goto done;
+ }
/* read the version */
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + PRECOMPILED_CONSTANT_LENGTH) > size) {
+ val = read_uint32(buf, &offset);
+ if ((val + PRECOMPILED_PKG_CONSTANT_LENGTH) > size) {
ui_expert(op, "Invalid file '%s' (bad version string length %d).",
filename, val);
goto done;
@@ -229,34 +232,28 @@ PrecompiledInfo *precompiled_unpack(Options *op,
/* check if this precompiled kernel interface is the right driver
version */
- if (strcmp(version, package_version) != 0) {
+ if (package_version && (strcmp(version, package_version) != 0)) {
goto done;
}
/* read the description */
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + PRECOMPILED_CONSTANT_LENGTH) > size) {
+ val = read_uint32(buf, &offset);
+ if ((val + PRECOMPILED_PKG_CONSTANT_LENGTH) > size) {
ui_expert(op, "Invalid file '%s' (bad description string length %d).",
filename, val);
goto done;
}
- if (val > 0) {
- description = nvalloc(val+1);
- memcpy(description, buf + offset, val);
- description[val] = '\0';
- } else {
- description = NULL;
- }
+ description = nvalloc(val+1);
+ memcpy(description, buf + offset, val);
+ description[val] = '\0';
offset += val;
/* read the proc version string */
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + PRECOMPILED_CONSTANT_LENGTH) > size) {
+ val = read_uint32(buf, &offset);
+ if ((val + PRECOMPILED_PKG_CONSTANT_LENGTH) > size) {
ui_expert(op, "Invalid file '%s' (bad version string length %d).",
filename, val);
goto done;
@@ -266,131 +263,686 @@ PrecompiledInfo *precompiled_unpack(Options *op,
offset += val;
proc_version_string[val] = '\0';
- /* if this interface appears to have been packaged by nvidia-installer,
- * get the linked module crc and path to the detached signature. */
-
- if (strstr(filename, PRECOMPILED_KERNEL_INTERFACE_FILENAME) ==
- strrchr(filename, '/') + 1) {
- char *suffix, *dirname, *tmp, *crc_file_path;
-
- dirname = nvstrdup(filename);
- tmp = strrchr(dirname, '/');
- *tmp = '\0';
-
- suffix = nvstrdup(strrchr(filename, '/') + 1 +
- strlen(PRECOMPILED_KERNEL_INTERFACE_FILENAME));
-
- detached_signature = nvstrcat(dirname, "/", DETACHED_SIGNATURE_FILENAME,
- suffix, NULL);
- crc_file_path = nvstrcat(dirname, "/", KERNEL_MODULE_CHECKSUM_FILENAME,
- suffix, NULL);
-
- if (access(detached_signature, F_OK | R_OK) == 0 &&
- access(crc_file_path, F_OK | R_OK) == 0) {
- FILE *crc_file;
-
- crc_file = fopen(crc_file_path, "r");
- if (crc_file) {
- int items_read = fread(&linked_module_crc,
- sizeof(linked_module_crc), 1, crc_file);
- if (items_read != 1) {
- ui_warn(op, "A checksum file for a linked kernel module "
- "was found, but reading the checksum failed.");
- detached_signature = NULL;
- }
- fclose(crc_file);
- }
- } else {
- detached_signature = NULL;
- }
- }
-
/* check if the running kernel matches */
- if (strcmp(real_proc_version_string, proc_version_string) != 0) {
+ if (real_proc_version_string &&
+ (strcmp(real_proc_version_string, proc_version_string) != 0)) {
goto done;
}
ui_log(op, "A precompiled kernel interface for kernel '%s' has been "
"found here: %s.", description, filename);
-
- /* extract kernel interface module */
-
- len = size - offset;
- if ((dst_fd = open(output_filename, O_CREAT | O_RDWR | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
- ui_error(op, "Unable to open output file '%s' (%s).", output_filename,
- strerror(errno));
- goto done;
- }
-
- /* set the output file length */
+ num_files = read_uint32(buf, &offset);
+ fileInfos = nvalloc(num_files * sizeof(PrecompiledFileInfo));
+ for (i = 0; i < num_files; i++) {
+ int ret;
+ ret = precompiled_read_fileinfo(op, fileInfos, i, buf, offset, size);
- if ((lseek(dst_fd, len - 1, SEEK_SET) == -1) ||
- (write(dst_fd, "", 1) == -1)) {
- ui_error(op, "Unable to set output file '%s' length %d (%s).\n",
- output_filename, len, strerror(errno));
- goto done;
+ if (ret > 0) {
+ offset += ret;
+ } else {
+ ui_log(op, "An error occurred while trying to parse '%s'.",
+ filename);
+ goto done;
+ }
}
- /* mmap the dst */
-
- dst = mmap(0, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, dst_fd, 0);
- if (dst == (void *) -1) {
- ui_error(op, "Unable to mmap output file %s (%s).\n",
- output_filename, strerror(errno));
- goto done;
- }
-
- /* copy */
-
- memcpy(dst, buf + offset, len);
-
/*
* now that we can no longer fail, allocate and initialize the
* PrecompiledInfo structure
*/
info = (PrecompiledInfo *) nvalloc(sizeof(PrecompiledInfo));
- info->crc = crc;
+ info->package_size = size;
info->version = version;
info->proc_version_string = proc_version_string;
info->description = description;
- info->detached_signature = detached_signature;
- info->linked_module_crc = linked_module_crc;
+ info->num_files = num_files;
+ info->files = fileInfos;
/*
- * XXX so that the proc version, description, and detached_signature strings
- * aren't freed below
+ * XXX so that the proc version and description strings, and the
+ * PrecompiledFileInfo array aren't freed below
*/
-
- proc_version_string = description = detached_signature = NULL;
+
+ proc_version_string = description = NULL;
+ fileInfos = NULL;
done:
-
+
/* cleanup whatever needs cleaning up */
- if (dst) munmap(dst, len);
if (buf) munmap(buf, size);
if (fd > 0) close(fd);
- if (dst_fd > 0) close(dst_fd);
if (description) free(description);
if (proc_version_string) free(proc_version_string);
- if (detached_signature) free(detached_signature);
+ if (fileInfos) free(fileInfos);
return info;
-
-} /* mkprecompiled_unpack() */
+}
+
+
+/*
+ * precompiled_file_unpack() - Unpack an individual precompiled file to the
+ * specified output directory.
+ */
+
+int precompiled_file_unpack(Options *op, const PrecompiledFileInfo *fileInfo,
+ const char *output_directory)
+{
+ int ret = FALSE, dst_fd = 0;
+ char *dst_path, *dst = NULL;
+
+ dst_path = nvstrcat(output_directory, "/", fileInfo->name, NULL);
+
+ /* extract file */
+
+ if ((dst_fd = open(dst_path, O_CREAT | O_RDWR | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
+ ui_error(op, "Unable to open output file '%s' (%s).", dst_path,
+ strerror(errno));
+ goto done;
+ }
+
+ /* set the output file length */
+
+ if ((lseek(dst_fd, fileInfo->size - 1, SEEK_SET) == -1) ||
+ (write(dst_fd, "", 1) == -1)) {
+ ui_error(op, "Unable to set output file '%s' length %d (%s).\n",
+ dst_path, fileInfo->size, strerror(errno));
+ goto done;
+ }
+
+ /* mmap the dst */
+
+ dst = mmap(0, fileInfo->size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, dst_fd, 0);
+ if (dst == (void *) -1) {
+ ui_error(op, "Unable to mmap output file %s (%s).\n",
+ dst_path, strerror(errno));
+ goto done;
+ }
+
+ /* copy */
+
+ memcpy(dst, fileInfo->data, fileInfo->size);
+
+ ret = TRUE;
+
+done:
+
+ /* cleanup whatever needs cleaning up */
+
+ nvfree(dst_path);
+ if (dst) munmap(dst, fileInfo->size);
+ if (dst_fd > 0) close(dst_fd);
+
+ return ret;
+}
+
+
+/* precompiled_unpack() - unpack all of the files in a PrecompiledInfo into
+ * the given destination directory */
+int precompiled_unpack(Options *op, const PrecompiledInfo *info,
+ const char *output_directory)
+{
+ int i;
+
+ if (!info) {
+ return FALSE;
+ }
+
+ for (i = 0; i < info->num_files; i++) {
+ if (!precompiled_file_unpack(op, &(info->files[i]), output_directory)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+/*
+ * encode_uint32() - given a uint32, a data buffer, and an offset into the data
+ * buffer, write the integer to the data buffer and advance the offset by the
+ * number of bytes written.
+ */
+
+static void encode_uint32(uint32 val, uint8 *data, int *offset)
+{
+ data[*offset + 0] = ((val >> 0) & 0xff);
+ data[*offset + 1] = ((val >> 8) & 0xff);
+ data[*offset + 2] = ((val >> 16) & 0xff);
+ data[*offset + 3] = ((val >> 24) & 0xff);
+
+ *offset += sizeof(uint32);
+}
+
+
+/*
+ * precompiled_pack() - pack the specified precompiled kernel interface
+ * file, prepended with a header, the CRC the driver version, a description
+ * string, and the proc version string.
+ */
+
+int precompiled_pack(const PrecompiledInfo *info, const char *package_filename)
+{
+ int fd, offset;
+ uint8 *out;
+ int version_len, description_len, proc_version_len;
+ int total_len, files_len, i;
+
+ /*
+ * get the lengths of the description, the proc version string,
+ * and the files to be packaged along with the associated metadata.
+ */
+
+ version_len = strlen(info->version);
+ description_len = strlen(info->description);
+ proc_version_len = strlen(info->proc_version_string);
+
+ for (files_len = i = 0; i < info->num_files; i++) {
+ files_len += PRECOMPILED_FILE_CONSTANT_LENGTH +
+ strlen(info->files[i].name) +
+ strlen(info->files[i].linked_module_name) +
+ strlen(info->files[i].core_object_name) +
+ info->files[i].size +
+ info->files[i].signature_size;
+ }
+
+ total_len = PRECOMPILED_PKG_CONSTANT_LENGTH +
+ version_len + description_len + proc_version_len + files_len;
+
+ /* open the output file for writing */
+
+ fd = nv_open(package_filename, O_CREAT|O_RDWR|O_TRUNC,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+ /* set the output file length */
+
+ nv_set_file_length(package_filename, fd, total_len);
+
+ /* map the output file */
+
+ out = nv_mmap(package_filename, total_len, PROT_READ|PROT_WRITE,
+ MAP_FILE|MAP_SHARED, fd);
+ offset = 0;
+
+ /* write the header */
+
+ memcpy(&(out[0]), PRECOMPILED_PKG_HEADER, 8);
+ offset += 8;
+
+ /* write the package version */
+
+ encode_uint32(PRECOMPILED_PKG_VERSION, out, &offset);
+
+ /* write the version */
+
+ encode_uint32(version_len, out, &offset);
+
+ if (version_len) {
+ memcpy(&(out[offset]), info->version, version_len);
+ offset += version_len;
+ }
+
+ /* write the description */
+
+ encode_uint32(description_len, out, &offset);
+
+ if (description_len) {
+ memcpy(&(out[offset]), info->description, description_len);
+ offset += description_len;
+ }
+
+ /* write the proc version string */
+
+ encode_uint32(proc_version_len, out, &offset);
+
+ memcpy(&(out[offset]), info->proc_version_string, proc_version_len);
+ offset += proc_version_len;
+
+ /* write the number of files */
+
+ encode_uint32(info->num_files, out, &offset);
+
+ /* write the files */
+ for (i = 0; i < info->num_files; i++) {
+ PrecompiledFileInfo *file = &(info->files[i]);
+ uint32 name_len = strlen(file->name);
+ uint32 linked_module_name_len = strlen(file->linked_module_name);
+ uint32 core_object_name_len = strlen(file->core_object_name);
+
+ /* file header */
+ memcpy(&(out[offset]), PRECOMPILED_FILE_HEADER, 4);
+ offset += 4;
+
+ /* file sequence number */
+ encode_uint32(i, out, &offset);
+
+ /* file type and attributes*/
+ encode_uint32(file->type, out, &offset);
+ encode_uint32(file->attributes, out, &offset);
+
+ /* file name */
+ encode_uint32(name_len, out, &offset);
+ memcpy(&(out[offset]), file->name, name_len);
+ offset += name_len;
+
+ /* linked module name */
+ encode_uint32(linked_module_name_len, out, &offset);
+ memcpy(&(out[offset]), file->linked_module_name, linked_module_name_len);
+ offset += linked_module_name_len;
+
+ /* core object name */
+ encode_uint32(core_object_name_len, out, &offset);
+ memcpy(&(out[offset]), file->core_object_name, core_object_name_len);
+ offset += core_object_name_len;
+
+ /* crc */
+ encode_uint32(file->crc, out, &offset);
+
+ /* file */
+ encode_uint32(file->size, out, &offset);
+ memcpy(&(out[offset]), file->data, file->size);
+ offset += file->size;
+
+ /* redundant crc */
+ encode_uint32(file->crc, out, &offset);
+
+ /* linked module crc */
+ encode_uint32(file->linked_module_crc, out, &offset);
+
+ /* detached signature */
+ encode_uint32(file->signature_size, out, &offset);
+ if (file->signature_size) {
+ memcpy(&(out[offset]), file->signature, file->signature_size);
+ offset += file->signature_size;
+ }
+
+ /* redundant file sequence number */
+ encode_uint32(i, out, &offset);
+
+ /* file footer */
+ memcpy(&(out[offset]), PRECOMPILED_FILE_FOOTER, 4);
+ offset += 4;
+ }
+
+ /* unmap package */
+
+ munmap(out, total_len);
+
+ close(fd);
+
+ return TRUE;
+
+}
+
+
+
/*
* free_precompiled() - free any malloced strings stored in a PrecompiledInfo,
* then free the PrecompiledInfo.
*/
void free_precompiled(PrecompiledInfo *info)
{
+ int i;
+
+ if (!info) {
+ return;
+ }
+
nvfree(info->description);
nvfree(info->proc_version_string);
- nvfree(info->detached_signature);
+ nvfree(info->version);
+
+ for (i = 0; i < info->num_files; i++) {
+ free_precompiled_file_data(info->files[i]);
+ }
+ nvfree(info->files);
+
nvfree(info);
}
+
+
+
+void free_precompiled_file_data(PrecompiledFileInfo fileInfo)
+{
+ nvfree(fileInfo.name);
+ nvfree(fileInfo.linked_module_name);
+ nvfree(fileInfo.data);
+ nvfree(fileInfo.signature);
+}
+
+
+
+/*
+ * precompiled_read_file() - attempt to open the file at the specified path and
+ * populate a PrecompiledFileInfo record with its contents and the appropriate
+ * metadata. Return a pointer to a newly allocated PrecompiledFile record on
+ * success, or NULL on failure.
+ */
+
+static int precompiled_read_file(PrecompiledFileInfo *fileInfo,
+ const char *filename,
+ const char *linked_module_name,
+ const char *core_object_name, uint32 type)
+{
+ int fd;
+ struct stat st;
+ int success = FALSE, ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ goto done;
+ }
+
+ if (fstat(fd, &st) != 0) {
+ goto done;
+ }
+
+ fileInfo->size = st.st_size;
+ fileInfo->data = nvalloc(fileInfo->size);
+
+ ret = read(fd, fileInfo->data, fileInfo->size);
+
+ if (ret != fileInfo->size) {
+ goto done;
+ }
+
+ fileInfo->type = type;
+ fileInfo->name = nv_basename(filename);
+ fileInfo->linked_module_name = nvstrdup(linked_module_name);
+ fileInfo->core_object_name = nvstrdup(core_object_name);
+ fileInfo->crc = compute_crc(NULL, filename);
+
+ success = TRUE;
+
+done:
+ close(fd);
+ return success;
+}
+
+
+int precompiled_read_interface(PrecompiledFileInfo *fileInfo,
+ const char *filename,
+ const char *linked_module_name,
+ const char *core_object_name)
+{
+ return precompiled_read_file(fileInfo, filename, linked_module_name,
+ core_object_name,
+ PRECOMPILED_FILE_TYPE_INTERFACE);
+}
+
+int precompiled_read_module(PrecompiledFileInfo *fileInfo, const char *filename)
+{
+ return precompiled_read_file(fileInfo, filename, "", "",
+ PRECOMPILED_FILE_TYPE_MODULE);
+}
+
+
+
+/*
+ * precompiled_read_fileinfo() - Read a PrecompiledFileInfo record from a binary
+ * precompiled file package.
+ *
+ * Parameters:
+ * op: A pointer to the options structure, used for ui_* functions
+ * fileInfos: A PrecompiledFileInfo array, where the decoded file data from
+ * the binary package will be stored
+ * index: The index into fileInfos where the decoded file data will be
+ * stored. Used to verify that the file number recorded in the
+ * package is valid.
+ * buf: The raw buffer containing the binary package data. This should
+ * point to the beginning of the package file.
+ * offset: The offset into buf where the file data to be read begins.
+ * size: The size of the package data buffer. This is used for bounds
+ * checking, to make sure that a reading a length specified in the
+ * won't go past the end of the package file.
+ *
+ * Return value:
+ * The number of bytes read from the package file on success, or -1 on error.
+ */
+
+static int precompiled_read_fileinfo(Options *op, PrecompiledFileInfo *fileInfos,
+ int index, char *buf, int offset, int size)
+{
+ PrecompiledFileInfo *fileInfo = fileInfos + index;
+ uint32 val;
+ int oldoffset = offset;
+
+ if (size - offset < PRECOMPILED_FILE_CONSTANT_LENGTH) {
+ return -1;
+ }
+
+ if (strncmp(buf + offset, PRECOMPILED_FILE_HEADER, 4) != 0) {
+ ui_log(op, "Unrecognized header for packaged file.");
+ return -1;
+ }
+ offset += 4;
+
+ val = read_uint32(buf, &offset);
+ if (val != index) {
+ ui_log(op, "Invalid file index %d; expected %d.", val, index);
+ return -1;
+ }
+
+ fileInfo->type = read_uint32(buf, &offset);
+ fileInfo->attributes = read_uint32(buf, &offset);
+
+ val = read_uint32(buf, &offset);
+ if (offset + val > size) {
+ ui_log(op, "Bad filename length.");
+ return -1;
+ }
+
+ fileInfo->name = nvalloc(val + 1);
+ memcpy(fileInfo->name, buf + offset, val);
+ offset += val;
+
+ val = read_uint32(buf, &offset);
+ if (offset + val > size) {
+ ui_log(op, "Bad linked module name length.");
+ return -1;
+ }
+
+ fileInfo->linked_module_name = nvalloc(val + 1);
+ memcpy(fileInfo->linked_module_name, buf + offset, val);
+ offset += val;
+
+ val = read_uint32(buf, &offset);
+ if (offset + val > size) {
+ ui_log(op, "Bad core object file name length.");
+ return -1;
+ }
+
+ fileInfo->core_object_name = nvalloc(val + 1);
+ memcpy(fileInfo->core_object_name, buf + offset, val);
+ offset += val;
+
+ fileInfo->crc = read_uint32(buf, &offset);
+
+ fileInfo->size = read_uint32(buf, &offset);
+ if (offset + fileInfo->size > size) {
+ ui_log(op, "Bad file length.");
+ return -1;
+ }
+
+ fileInfo->data = nvalloc(fileInfo->size);
+ memcpy(fileInfo->data, buf + offset, fileInfo->size);
+ offset += fileInfo->size;
+
+ val = read_uint32(buf, &offset);
+ if (val != fileInfo->crc) {
+ ui_log(op, "The redundant stored CRC values %" PRIu32 " and %" PRIu32
+ " disagree with each other; the file may be corrupted.",
+ fileInfo->crc, val);
+ return -1;
+ }
+
+ val = compute_crc_from_buffer(fileInfo->data, fileInfo->size);
+ if (val != fileInfo->crc) {
+ ui_log(op, "The CRC for the file '%s' (%" PRIu32 ") does not match the "
+ "expected value (%" PRIu32 ").", fileInfo->name, val,
+ fileInfo->crc);
+ }
+
+ fileInfo->linked_module_crc = read_uint32(buf, &offset);
+
+ fileInfo->signature_size = read_uint32(buf, &offset);
+ if(fileInfo->signature_size) {
+ if (offset + fileInfo->signature_size > size) {
+ ui_log(op, "Bad signature size");
+ return -1;
+ }
+ fileInfo->signature = nvalloc(fileInfo->signature_size);
+ memcpy(fileInfo->signature, buf + offset, fileInfo->signature_size);
+ offset += fileInfo->signature_size;
+ }
+
+ val = read_uint32(buf, &offset);
+ if (val != index) {
+ ui_log(op, "Invalid file index %d; expected %d.", val, index);
+ return -1;
+ }
+
+ if (strncmp(buf + offset, PRECOMPILED_FILE_FOOTER, 4) != 0) {
+ ui_log(op, "Unrecognized footer for packaged file.");
+ return -1;
+ }
+ offset += 4;
+
+ return offset - oldoffset;
+}
+
+
+/*
+ * precompiled_find_file() - search for a file with the given name within the
+ * given PrecompiledInfo record, and return a pointer to it if found, or NULL
+ * if not found.
+ */
+
+PrecompiledFileInfo *precompiled_find_file(const PrecompiledInfo *info,
+ const char *file)
+{
+ int i;
+
+ for (i = 0; i < info->num_files; i++) {
+ if (strcmp(file, info->files[i].name) == 0) {
+ return info->files + i;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * precompiled_append_files() - append the given PrecompiledFileInfo array to
+ * the already existing files in the given PrecompiledInfo.
+ */
+
+void precompiled_append_files(PrecompiledInfo *info, PrecompiledFileInfo *files,
+ int num_files)
+{
+ info->files = nvrealloc(info->files, (info->num_files + num_files) *
+ sizeof(PrecompiledFileInfo));
+ memcpy(info->files + info->num_files, files,
+ num_files * sizeof(PrecompiledFileInfo));
+ info->num_files += num_files;
+}
+
+/*
+ * precompiled_file_type_name() - return a pointer to a human-readable string
+ * naming a file type. The string should not be freed.
+ */
+const char *precompiled_file_type_name(uint32 file_type)
+{
+ static const char *file_type_names[] = {
+ "precompiled kernel interface",
+ "precompiled kernel module",
+ };
+
+ if (file_type >= ARRAY_LEN(file_type_names)) {
+ return "unknown file type";
+ }
+
+ return file_type_names[file_type];
+}
+
+/*
+ * precompiled_file_attribute_names() - return a NULL-terminated list of
+ * human-readable strings naming the attributes in the given file attribute
+ * mask. The list should be freed when no longer used, but the constituent
+ * strings should not be freed.
+ */
+const char **precompiled_file_attribute_names(uint32 attribute_mask)
+{
+ const char **ret;
+ int i, attr = 0;
+
+ static const char *file_attribute_names[] = {
+ "detached signature",
+ "linked module crc",
+ "embedded signature",
+ };
+
+ ret = nvalloc((ARRAY_LEN(file_attribute_names) + 1) * sizeof(char *));
+
+ for (i = 0; i < 32; i++) {
+ if (attribute_mask & (1 << i)) {
+ ret[attr++] = file_attribute_names[i];
+ }
+ }
+ ret[attr] = NULL;
+
+ return ret;
+}
+
+
+
+/*
+ * byte_tail() - copy from infile, starting at the specified byte offset, and
+ * going until the end of infile to a newly allocated buffer, a pointer to
+ * which is stored at location given by the caller. Returns the size of the new
+ * buffer on success; returns 0 and sets the caller pointer to NULL on failure.
+ * This is needed because `tail -c` is unreliable in some implementations.
+ */
+int byte_tail(const char *infile, int start, char **buf)
+{
+ FILE *in = NULL;
+ int ret, end, size = 0;
+
+ in = fopen(infile, "r");
+
+ if (!in) {
+ goto done;
+ }
+
+ ret = fseek(in, 0, SEEK_END);
+ if (ret != 0) {
+ goto done;
+ }
+ end = ftell(in);
+
+ ret = fseek(in, start, SEEK_SET);
+ if (ret != 0) {
+ goto done;
+ }
+
+ size = end - start;
+ *buf = nvalloc(size);
+
+ ret = (fread(*buf, 1, size + 1, in));
+ if (ret != size || ferror(in) || !feof(in)) {
+ nvfree(*buf);
+ *buf = NULL;
+ goto done;
+ }
+
+done:
+ fclose(in);
+ return size;
+}