diff options
author | Uwe Hermann <uwe@hermann-uwe.de> | 2008-11-02 17:01:06 +0000 |
---|---|---|
committer | Uwe Hermann <uwe@hermann-uwe.de> | 2008-11-02 17:01:06 +0000 |
commit | 7eb845e815924984b301aaf674b090cde28c1c6a (patch) | |
tree | d85a1080fd20b0ad8e1859d012fe90ba9cdf1cd9 /payloads/bayou/util/pbuilder/liblar/lib.c | |
parent | 91df5619dbb7d2064f9947f2fbc56477f7b707c3 (diff) | |
download | coreboot-7eb845e815924984b301aaf674b090cde28c1c6a.tar.xz |
Import a slightly modified Bayou version into svn. This is based
on the last snapshot posted by Jordan Crouse. This commit is long
overdue.
Changes by me include:
- Rename 'utils' to 'util' for consistency with our other projects.
- Move the main code out of src/* into the top-level directory.
- Add missing license headers to the following files:
Makefile, pbuilder/liblar/Makefile, util/pbuilder/Makefile.
- Dropped the util/pbuilder/lzma completely. I'm working on reusing
the lzma/ dir from v3 via svn:externals. Alas, this also means
that Bayou won't yet compile out of the box.
- Coding-style and white-space fixes (indent) for all files.
Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3719 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'payloads/bayou/util/pbuilder/liblar/lib.c')
-rw-r--r-- | payloads/bayou/util/pbuilder/liblar/lib.c | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/payloads/bayou/util/pbuilder/liblar/lib.c b/payloads/bayou/util/pbuilder/liblar/lib.c new file mode 100644 index 0000000000..f0e0a41bd4 --- /dev/null +++ b/payloads/bayou/util/pbuilder/liblar/lib.c @@ -0,0 +1,461 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <arpa/inet.h> + +#include "liblar.h" +#include "self.h" + +static int lar_compress(struct LAR *lar, int algo, char *src, char *dst, + int len) +{ + int ret; + + if (!lar->cfuncs[algo]) + return -1; + + lar->cfuncs[algo] (src, len, dst, &ret); + return ret; +} + +static int lar_decompress(struct LAR *lar, int algo, char *src, char *dst, + int slen, int dlen) +{ + if (!lar->dfuncs[algo]) + return -1; + + lar->dfuncs[algo] (src, slen, dst, dlen); + return dlen; +} + +static struct LARHeader *lar_get_header(struct LAR *lar, const char *filename) +{ + char *buffer; + int offset = 0; + struct LARHeader *lheader = NULL; + struct lar_header *header; + + printf("Getting %s\n", filename); + + buffer = malloc(sizeof(struct lar_header) + MAX_PATHLEN); + + if (buffer == NULL) + return NULL; + + while (1) { + int ret; + + if (lseek(lar->fd, offset, SEEK_SET) == -1) + goto err; + + ret = read(lar->fd, buffer, sizeof(struct lar_header)); + + if (ret <= 0) + goto err; + + header = (struct lar_header *)buffer; + + if (strncmp(header->magic, MAGIC, sizeof(MAGIC))) + goto err; + + ret = read(lar->fd, buffer + sizeof(struct lar_header), + ntohl(header->offset) - sizeof(struct lar_header)); + + if (ret <= 0) + goto err; + + if (!strcmp(buffer + sizeof(struct lar_header), filename)) + break; + + offset += ntohl(header->offset) + + ((ntohl(header->len) + 15) & ~0xF); + } + + lheader = calloc(sizeof(struct LARHeader), 1); + + if (lheader == NULL) + goto err; + + lheader->hoffset = offset; + lheader->offset = offset + ntohl(header->offset); + + lheader->reallen = ntohl(header->reallen); + lheader->len = ntohl(header->len); + + lheader->loadaddress = ntohl(header->loadaddress); + lheader->compression = ntohl(header->compression); + lheader->entry = ntohl(header->entry); + lheader->checksum = ntohl(header->checksum); + +err: + free(buffer); + return lheader; +} + +static int LAR_AppendBlob(struct LAR *lar, unsigned char *buffer, + int len, int rlen, struct LARAttr *attr) +{ + int nlen, nsize, lsize, i; + struct lar_header *header; + u8 *lptr; + u32 csum = 0; + + if (attr == NULL) + return -1; + + nlen = strlen(attr->name) + 1; + + if (nlen > MAX_PATHLEN - 1) + nlen = MAX_PATHLEN - 1; + + nsize = (nlen + 15) & ~0xF; + + lsize = sizeof(struct lar_header) + nsize + len; + lptr = calloc(lsize + 1, 1); + + if (lptr == NULL) + return -1; + + header = (struct lar_header *)lptr; + + memcpy(header->magic, MAGIC, 8); + header->reallen = htonl(rlen); + header->len = htonl(len); + header->offset = htonl(lsize - len); + header->loadaddress = htonl(attr->loadaddr); + header->compression = htonl(attr->compression); + header->entry = htonl(attr->entry); + + strncpy(((char *)header) + sizeof(struct lar_header), attr->name, nlen); + + for (i = 0; i < sizeof(struct lar_header) + nsize; i += 4) + csum += *((u32 *) (lptr + i)); + + for (i = 0; i < len; i += 4) { + /* + * The checksum needs to include the 16 byte padding at + * the end of the data before the next lar header. The + * problem is that the padding isn't going to be in the + * buffer, and if we try to read off the end of the buffer, + * we are just asking for trouble. So account for the + * situation where the datalen is not a multiple of four + * and get a safe value to add into the checksum. + * The rest of the padding will be zero, and can be safely + * ignored here. + */ + if ((len - i) < 4) { + u32 val = 0; + int t; + + for (t = 0; t < (len - i); t++) + val |= *((u8 *) buffer + (i + t)) << (t * 8); + csum += val; + } else + csum += *((u32 *) (buffer + i)); + } + + header->checksum = (u32) (~0 - csum); + + lseek(lar->fd, 0, SEEK_END); + + /* FIXME: Error check here. */ + + write(lar->fd, header, sizeof(struct lar_header) + nsize); + write(lar->fd, buffer, len); + + /* Add in padding to the next 16 byte boundary. */ + if (lsize & 0xF) { + int i; + char null = '\0'; + + for (i = lsize & 0xF; i < 0x10; i++) + write(lar->fd, &null, 1); + } + + return 0; +} + +int LAR_AppendBuffer(struct LAR *lar, unsigned char *buffer, int len, + struct LARAttr *attr) +{ + unsigned char *tbuf; + int rlen, ret = -1; + + if (attr->compression == ALGO_NONE) + return LAR_AppendBlob(lar, buffer, len, len, attr); + + tbuf = malloc(len); + + if (tbuf == NULL) + return -1; + + rlen = lar_compress(lar, attr->compression, (char *)buffer, + (char *)tbuf, len); + + if (rlen > 0) + ret = LAR_AppendBlob(lar, tbuf, rlen, len, attr); + + free(tbuf); + return ret; +} + +int LAR_AppendSelf(struct LAR *lar, const char *filename, struct LARAttr *attr) +{ + unsigned char *buffer; + int len = elf_to_self(filename, &buffer, + lar->cfuncs[attr->compression]); + int ret; + + if (len == -1) + return -1; + + ret = LAR_AppendBlob(lar, buffer, len, len, attr); + free(buffer); + + return ret; +} + +int LAR_AppendFile(struct LAR *lar, const char *filename, struct LARAttr *attr) +{ + int fd; + struct stat s; + char *filep; + int ret; + + if (iself((char *)filename)) + return LAR_AppendSelf(lar, filename, attr); + + fd = open(filename, O_RDONLY); + + if (fd == -1) + return -1; + + if (fstat(fd, &s)) + return -1; + + filep = (char *)mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); + + if (filep == MAP_FAILED) + return -1; + + ret = LAR_AppendBuffer(lar, (unsigned char *)filep, s.st_size, attr); + + munmap(filep, s.st_size); + return ret; +} + +int LAR_DeleteFile(struct LAR *lar, const char *filename) +{ + struct LARHeader *header = lar_get_header(lar, filename); + int len, ret = -1; + char *filep, *buffer; + + if (header == NULL) + return -1; + + buffer = malloc(4096); + if (buffer == NULL) + return -1; + + len = header->offset + header->len; + + /* First, map the space and zero it out. */ + + filep = (char *)mmap(0, len, PROT_READ, MAP_SHARED, lar->fd, + header->hoffset); + + if (filep == MAP_FAILED) + return -1; + + memset(filep, 0, len); + munmap(filep, len); + + /* Now move the rest of the LAR into place. */ + /* FIXME: This does not account for the bootblock! */ + + int dst = header->hoffset; + int src = header->hoffset + len; + + while (1) { + int l, w; + + if (lseek(lar->fd, src, SEEK_SET)) + goto err; + + l = read(lar->fd, buffer, 8192); + + if (l == -1) + goto err; + if (l == 0) + goto err; + if (lseek(lar->fd, dst, SEEK_SET)) + goto err; + + w = write(lar->fd, buffer, l); + + if (w <= 0) + goto err; + + dst += w; + src += w; + } + + ret = 0; + +err: + free(buffer); + return ret; +} + +void LAR_CloseFile(struct LARFile *file) +{ + if (file != NULL) { + if (file->buffer != NULL) + free(file->buffer); + free(file); + } +} + +struct LARFile *LAR_MapFile(struct LAR *lar, const char *filename) +{ + struct LARFile *file; + struct LARHeader *header = lar_get_header(lar, filename); + char *filep; + int ret; + + if (header == NULL) + return NULL; + + file = calloc(sizeof(struct LARFile), 1); + + if (file == NULL) + return NULL; + + file->len = header->reallen; + file->buffer = calloc(header->reallen, 1); + + if (file->buffer == NULL) + goto err; + + /* + * The offset needs to be a multiple of PAGE_SIZE, so just mmap + * from offset 0, its easier then doing the math. + */ + + filep = mmap(0, header->offset + header->len, + PROT_READ, MAP_SHARED, lar->fd, 0); + + if (filep == MAP_FAILED) { + printf("Map failed: %m\n"); + goto err; + } + + if (header->compression != ALGO_NONE) { + ret = lar_decompress(lar, header->compression, + filep + header->offset, file->buffer, + header->len, header->reallen); + } else { + memcpy(file->buffer, filep + header->offset, header->len); + ret = header->len; + } + + munmap(filep, header->offset + header->len); + + if (ret == header->reallen) + return file; + +err: + if (file->buffer) + free(file->buffer); + + free(file); + return NULL; +} + +int LAR_SetCompressionFuncs(struct LAR *lar, int algo, + LAR_CompFunc cfunc, LAR_DecompFunc dfunc) +{ + + if (algo >= ALGO_INVALID) + return -1; + + lar->cfuncs[algo] = cfunc; + lar->dfuncs[algo] = dfunc; + + return 0; +} + +void LAR_Close(struct LAR *lar) +{ + if (lar != NULL) { + if (lar->fd) + close(lar->fd); + + free(lar); + } +} + +struct LAR *LAR_Open(const char *filename) +{ + struct LAR *lar = calloc(sizeof(struct LAR), 1); + + if (lar == NULL) + return NULL; + + lar->fd = open(filename, O_RDWR); + + if (lar->fd > 0) + return lar; + + free(lar); + return NULL; +} + +struct LAR *LAR_Create(const char *filename) +{ + struct LAR *lar = calloc(sizeof(struct LAR), 1); + + if (lar == NULL) + return NULL; + + lar->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + + if (lar->fd > 0) + return lar; + + free(lar); + return NULL; +} + +void LAR_SetAttrs(struct LARAttr *attrs, char *name, int algo) +{ + if (attrs == NULL) + return; + + memset(attrs, 0, sizeof(*attrs)); + snprintf(attrs->name, sizeof(attrs->name) - 1, name); + attrs->compression = algo; +} |