diff options
author | Brad Bishop <bradleyb@us.ibm.com> | 2014-06-30 22:10:16 -0500 |
---|---|---|
committer | Patrick Williams <iawillia@us.ibm.com> | 2014-07-02 22:49:29 -0500 |
commit | bf4630076762d9c20c16c80c1c791f352b046dd1 (patch) | |
tree | efc67bad010a28fd1abf5aeeefda2a969514fd97 /ffs/src | |
download | ffs-bf4630076762d9c20c16c80c1c791f352b046dd1.tar.gz ffs-bf4630076762d9c20c16c80c1c791f352b046dd1.zip |
Port FFS tools over from Building Block repository.
Diffstat (limited to 'ffs/src')
-rw-r--r-- | ffs/src/ffs-fsp.h | 59 | ||||
-rw-r--r-- | ffs/src/libffs.c | 1520 | ||||
-rw-r--r-- | ffs/src/libffs2.c | 489 |
3 files changed, 2068 insertions, 0 deletions
diff --git a/ffs/src/ffs-fsp.h b/ffs/src/ffs-fsp.h new file mode 100644 index 0000000..f1b3374 --- /dev/null +++ b/ffs/src/ffs-fsp.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) International Business Machines Corp., 2014 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Copyright (c) International Business Machines Corp., 2012 + * + * FSP Flash Structure, Boot specific adaptations + */ + +#ifndef __FFS_BOOT_H__ +#define __FFS_BOOT_H__ + +#include "ffs.h" + +/* + * Values to use in USER_DATA_VOL + * + * @note: Side 0/1 must be defined as even/odd values. Code in the IPL depends + * on this to be able to use the appropriate volume based on the boot bank. + */ +enum vol { + FFS_VOL_IPL0 = 0, + FFS_VOL_IPL1 = 1, + FFS_VOL_SPL0 = 2, + FFS_VOL_SPL1 = 3, + FFS_VOL_BOOTENV0 = 4, + FFS_VOL_BOOTENV1 = 5, + FFS_VOL_KERNEL0 = 6, + FFS_VOL_KERNEL1 = 7, + FFS_VOL_INITRAMFS0 = 8, + FFS_VOL_INITRAMFS1 = 9, + FFS_VOL_DTB0 = 10, + FFS_VOL_DTB1 = 11, + FFS_VOL_SERIES0 = 12, + FFS_VOL_SERIES1 = 13, + FFS_VOL_CARD0 = 14, + FFS_VOL_CARD1 = 15, + FFS_VOL_DUMP0 = 16, + FFS_VOL_DUMP1 = 17, + FFS_VOL_DUMP2 = 18, + FFS_VOL_DUMP3 = 19, +}; + +#endif /* __FFS_BOOT_H__ */ diff --git a/ffs/src/libffs.c b/ffs/src/libffs.c new file mode 100644 index 0000000..b912ede --- /dev/null +++ b/ffs/src/libffs.c @@ -0,0 +1,1520 @@ +/* + * Copyright (c) International Business Machines Corp., 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * File: libffs.c + * Author: Shaun Wetzstein <shaun@us.ibm.com> + * Descr: FFS IO interface + * Note: + * Date: 05/07/12 + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdlib.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <endian.h> +#include <libgen.h> +#include <regex.h> + +#include "libffs.h" + +#include <clib/assert.h> +#include <clib/builtin.h> +#include <clib/checksum.h> +#include <clib/misc.h> +#include <clib/err.h> +#include <clib/raii.h> + +#ifndef be32toh +#include <byteswap.h> +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define be32toh(x) __bswap_32(x) +#define htobe32(x) __bswap_32(x) +#else +#define be32toh(x) (x) +#define htobe32(x) (x) +#endif +#endif + +#define FFS_ENTRY_EXTENT 10UL + +/* ============================================================ */ + +static void __hdr_be32toh(ffs_hdr_t * hdr) +{ + assert(hdr != NULL); + + hdr->magic = be32toh(hdr->magic); + hdr->version = be32toh(hdr->version); + hdr->size = be32toh(hdr->size); + hdr->entry_size = be32toh(hdr->entry_size); + hdr->entry_count = be32toh(hdr->entry_count); + hdr->block_size = be32toh(hdr->block_size); + hdr->block_count = be32toh(hdr->block_count); + hdr->checksum = be32toh(hdr->checksum); +} + +static void __hdr_htobe32(ffs_hdr_t * hdr) +{ + assert(hdr != NULL); + + hdr->magic = htobe32(hdr->magic); + hdr->version = htobe32(hdr->version); + hdr->size = htobe32(hdr->size); + hdr->entry_size = htobe32(hdr->entry_size); + hdr->entry_count = htobe32(hdr->entry_count); + hdr->block_size = htobe32(hdr->block_size); + hdr->block_count = htobe32(hdr->block_count); + hdr->checksum = htobe32(hdr->checksum); +} + +static void __entry_be32toh(ffs_entry_t * entry) +{ + assert(entry != NULL); + + entry->base = be32toh(entry->base); + entry->size = be32toh(entry->size); + entry->pid = be32toh(entry->pid); + entry->id = be32toh(entry->id); + entry->type = be32toh(entry->type); + entry->flags = be32toh(entry->flags); + entry->actual = be32toh(entry->actual); + entry->checksum = be32toh(entry->checksum); + + entry->resvd[0] = be32toh(entry->resvd[0]); + entry->resvd[1] = be32toh(entry->resvd[1]); + entry->resvd[2] = be32toh(entry->resvd[2]); + entry->resvd[3] = be32toh(entry->resvd[3]); + + for (int j = 0; j < FFS_USER_WORDS; j++) + entry->user.data[j] = be32toh(entry->user.data[j]); +} + +static void __entry_htobe32(ffs_entry_t * entry) +{ + assert(entry != NULL); + + entry->base = htobe32(entry->base); + entry->size = htobe32(entry->size); + entry->pid = htobe32(entry->pid); + entry->id = htobe32(entry->id); + entry->type = htobe32(entry->type); + entry->flags = htobe32(entry->flags); + entry->actual = htobe32(entry->actual); + entry->checksum = htobe32(entry->checksum); + + entry->resvd[0] = htobe32(entry->resvd[0]); + entry->resvd[1] = htobe32(entry->resvd[1]); + entry->resvd[2] = htobe32(entry->resvd[2]); + entry->resvd[3] = htobe32(entry->resvd[3]); + + for (int j = 0; j < FFS_USER_WORDS; j++) + entry->user.data[j] = htobe32(entry->user.data[j]); +} + +static int __hdr_read(ffs_hdr_t * hdr, FILE * file, off_t offset) +{ + assert(hdr != NULL); + + if (fseeko(file, offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + size_t rc = fread(hdr, 1, sizeof(*hdr), file); + if (rc <= 0 && ferror(file)) { + ERRNO(errno); + return -1; + } + + uint32_t ck = memcpy_checksum(NULL, (void *)hdr, + offsetof(ffs_hdr_t, checksum)); + + __hdr_be32toh(hdr); + + if (hdr->magic != FFS_MAGIC) { + ERROR(ERR_UNEXPECTED, FFS_CHECK_HEADER_MAGIC, + "magic number mismatch '%x' != '%x'", + hdr->magic, FFS_MAGIC); + return -1; + } + + if (hdr->checksum != ck) { + ERROR(ERR_UNEXPECTED, FFS_CHECK_HEADER_CHECKSUM, + "header checksum mismatch '%x' != '%x'", + hdr->checksum, ck); + return -1; + } + + return 0; +} + +static int __hdr_write(ffs_hdr_t * hdr, FILE * file, off_t offset) +{ + assert(hdr != NULL); + assert(hdr->magic == FFS_MAGIC); + + hdr->checksum = memcpy_checksum(NULL, (void *)hdr, + offsetof(ffs_hdr_t, checksum)); + hdr->checksum = htobe32(hdr->checksum); + + if (fseeko(file, offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + size_t size = sizeof(*hdr); + + if (0 < hdr->entry_count) { + size += hdr->entry_count * hdr->entry_size; + + for (size_t i=0; i<hdr->entry_count; i++) { + ffs_entry_t *e = hdr->entries + i; + + __entry_htobe32(e); + + e->checksum = memcpy_checksum(NULL, (void *)e, + offsetof(ffs_entry_t, + checksum)); + e->checksum = htobe32(e->checksum); + } + } + + __hdr_htobe32(hdr); + + size_t rc = fwrite(hdr, 1, size, file); + if (rc <= 0 && ferror(file)) { + ERRNO(errno); + return -1; + } + + __hdr_be32toh(hdr); + if (0 < hdr->entry_count) + for (size_t i=0; i<hdr->entry_count; i++) + __entry_be32toh(hdr->entries + i); + + return 0; +} + +static int __entries_read(ffs_hdr_t * hdr, FILE * file, off_t offset) +{ + assert(hdr != NULL); + assert(hdr->magic == FFS_MAGIC); + + if (0 < hdr->entry_count) { + if (fseeko(file, offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + size_t size = hdr->entry_count * hdr->entry_size; + + size_t rc = fread(hdr->entries, 1, size, file); + if (rc <= 0 && ferror(file)) { + ERRNO(errno); + return -1; + } + + for (size_t i=0; i<hdr->entry_count; i++) { + ffs_entry_t *e = hdr->entries + i; + + uint32_t ck = memcpy_checksum(NULL, (void *)e, + offsetof(ffs_entry_t, + checksum)); + __entry_be32toh(e); + + if (e->checksum != ck) { + ERROR(ERR_UNEXPECTED, FFS_CHECK_ENTRY_CHECKSUM, + "'%s' entry checksum mismatch '%x' != " + "'%x'", e->name, e->checksum, ck); + return -1; + } + } + } + + return 0; +} + +#if 0 +static void __entries_write(ffs_hdr_t * hdr, FILE * file, off_t offset) +{ + if (unlikely(hdr == NULL)) + ffs_throw(UNEX, 10400, "NULL hdr pointer"); + if (hdr->magic != FFS_MAGIC) + ffs_throw(UNEX, 10401, "magic number mismatch '%x' != " + "'%x'", hdr->magic, FFS_MAGIC); + + if (0 < hdr->entry_count) { + size_t size = hdr->entry_count * hdr->entry_size; + + for (size_t i = 0; i < hdr->entry_count; i++) { + ffs_entry_t *e = hdr->entries + i; + __entry_htobe32(e); + e->checksum = memcpy_checksum(NULL, (void *)e, + offsetof(ffs_entry_t, + checksum)); + e->checksum = htobe32(e->checksum); + } + + if (fseeko(file, offset, SEEK_SET) != 0) + ffs_throw(ERR, 10402, "%s (errno=%d)", + strerror(errno), errno); + + size_t rc = fwrite(hdr->entries, 1, size, file); + if (rc <= 0 && ferror(file)) + ffs_throw(ERR, 10403, "%s (errno=%d)", + strerror(errno), errno); + + fflush(file); + + for (size_t i = 0; i < hdr->entry_count; i++) + __entry_be32toh(hdr->entries + i); + } +} +#endif + +static ffs_entry_t *__iterate_entries(ffs_hdr_t * self, + int (*func) (ffs_entry_t *)) +{ + assert(self != NULL); + assert(func != NULL); + + for (uint32_t i = 0; i < self->entry_count; i++) { + if (func(self->entries + i) != 0) + return self->entries + i; + } + + return NULL; +} + +static ffs_entry_t *__find_entry(ffs_hdr_t * self, const char *path) +{ + assert(self != NULL); + + if (path == NULL || *path == '\0') + return NULL; + + if (*path == '/') + path++; + + char __path[strlen(path) + 1]; + strcpy(__path, path); + path = __path; + + ffs_entry_t root = {.id = FFS_PID_TOPLEVEL }, *parent = &root; + + char *name; + while (parent != NULL && (name = strtok((char *)path, "/")) != NULL) { + path = NULL; + + int find_entry(ffs_entry_t * child) { + return (parent->id == child->pid && + strncmp(name, child->name, + sizeof(child->name)) == 0); + } + + parent = __iterate_entries(self, find_entry); + } + + return parent; +} + +/* ============================================================ */ + +int __ffs_fcheck(FILE *file, off_t offset) +{ + assert(file != NULL); + + RAII(ffs_hdr_t*, hdr, malloc(sizeof(*hdr)), free); + if (hdr == NULL) { + ERRNO(errno); + return -1; + } + memset(hdr, 0, sizeof(*hdr)); + + if (fseeko(file, offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + if (fread(hdr, 1, sizeof(*hdr), file) <= 0 && ferror(file)) { + ERRNO(errno); + return -1; + } + + uint32_t ck = memcpy_checksum(NULL, (void *)hdr, + offsetof(ffs_hdr_t, checksum)); + __hdr_be32toh(hdr); + + if (hdr->magic != FFS_MAGIC) { + ERROR(ERR_UNEXPECTED, FFS_CHECK_HEADER_MAGIC, + "header magic mismatch '%x' != '%x'", + hdr->magic, FFS_MAGIC); + return FFS_CHECK_HEADER_MAGIC; + } + if (hdr->checksum != ck) { + ERROR(ERR_UNEXPECTED, FFS_CHECK_HEADER_CHECKSUM, + "header checksum mismatch '%x' != '%x'", + hdr->checksum, ck); + return FFS_CHECK_HEADER_CHECKSUM; + } + + size_t size = hdr->entry_count * hdr->entry_size; + + hdr = (ffs_hdr_t *)realloc(hdr, sizeof(*hdr) + size); + if (hdr == NULL) { + ERRNO(errno); + return -1; + } + memset(hdr->entries, 0, size); + + if (0 < hdr->entry_count) { + if (fread(hdr->entries, 1, size, file) <= 0 && ferror(file)) { + ERRNO(errno); + return -1; + } + + for (size_t i = 0; i < hdr->entry_count; i++) { + ffs_entry_t *e = hdr->entries + i; + + uint32_t ck = memcpy_checksum(NULL, (void *)e, + offsetof(ffs_entry_t, + checksum)); + + __entry_be32toh(e); + + if (e->checksum != ck) { + ERROR(ERR_UNEXPECTED, FFS_CHECK_ENTRY_CHECKSUM, + "'%s' entry checksum mismatch '%x' != " + "'%x'", e->name, e->checksum, ck); + return FFS_CHECK_ENTRY_CHECKSUM; + } + } + } + + return 0; +} + +int __ffs_check(const char *path, off_t offset) +{ + if (path == NULL || *path == '\0') { + UNEXPECTED("invalid path '%s'\n", path); + return -1; + } + + RAII(FILE*, file, fopen(path, "r"), fclose); + if (file == NULL) { + ERRNO(errno); + return -1; + } + + return __ffs_fcheck(file, offset); +} + +ffs_t *__ffs_fcreate(FILE *file, off_t offset, uint32_t block_size, + uint32_t block_count) +{ + assert(file != NULL); + + if (!is_pow2(block_size)) { + UNEXPECTED("'%d' invalid block size (must be non-0 and a " + "power of 2)", block_size); + return NULL; + } + if (!is_pow2(block_count)) { + UNEXPECTED("'%d' invalid block count (must be non-0 and a " + "power of 2)", block_count); + return NULL; + } + if (offset & (block_size - 1)) { + UNEXPECTED("'%lld' invalid offset (must be 'block size' " + "aligned)", offset); + return NULL; + } + + ffs_t *self = (ffs_t *) malloc(sizeof(*self)); + if (self == NULL) { + ERRNO(errno); + goto error; + } + + memset(self, 0, sizeof(*self)); + self->file = file; + self->offset = offset; + self->count = FFS_ENTRY_EXTENT; + self->dirty = true; + + self->hdr = (ffs_hdr_t *) malloc(sizeof(*self->hdr)); + if (self->hdr == NULL) { + ERRNO(errno); + goto error; + } + + self->hdr->magic = FFS_MAGIC; + self->hdr->version = FFS_VERSION_1; + self->hdr->size = 1; + self->hdr->entry_size = sizeof(*self->hdr->entries); + self->hdr->entry_count = 0; + self->hdr->block_size = block_size; + self->hdr->block_count = block_count; + self->hdr->checksum = 0; + + size_t size = self->count * self->hdr->entry_size; + + self->hdr = (ffs_hdr_t *) realloc(self->hdr, sizeof(*self->hdr) + size); + if (self->hdr == NULL) { + ERRNO(errno); + goto error; + } + memset(self->hdr->entries, 0, size); + + if (__ffs_entry_add(self, FFS_PARTITION_NAME, offset, block_size, + FFS_TYPE_PARTITION, FFS_FLAGS_PROTECTED) < 0) + goto error; + if (__ffs_entry_truncate(self, FFS_PARTITION_NAME, block_size) < 0) + goto error; + + if (false) { + error: + if (self != NULL) { + if (self->file != NULL) + fclose(self->file), self->file = NULL; + if (self->path != NULL) + free(self->path), self->path = NULL; + if (self->hdr != NULL) + free(self->hdr), self->hdr = NULL; + free(self), self = NULL; + } + } + + return self; +} + +ffs_t *__ffs_create(const char *path, off_t offset, uint32_t block_size, + uint32_t block_count) +{ + assert(path != NULL); + + FILE * file = fopen(path, "r+"); + if (file == NULL) { + ERRNO(errno); + return NULL; + } + + ffs_t * self = __ffs_fcreate(file, offset, block_size, block_count); + if (self != NULL) + self->path = strdup(path); + + return self; +} + +ffs_t *__ffs_fopen(FILE * file, off_t offset) +{ + assert(file != NULL); + + ffs_t *self = (ffs_t *) malloc(sizeof(*self)); + if (self == NULL) { + ERRNO(errno); + goto error; + } + + memset(self, 0, sizeof(*self)); + self->file = file; + self->count = 0; + self->offset = offset; + self->dirty = false; + + self->hdr = (ffs_hdr_t *) malloc(sizeof(*self->hdr)); + if (self->hdr == NULL) { + ERRNO(errno); + goto error; + } + memset(self->hdr, 0, sizeof(*self->hdr)); + + if (__hdr_read(self->hdr, self->file, self->offset) < 0) + goto error; + + self->count = max(self->hdr->entry_count, FFS_ENTRY_EXTENT); + size_t size = self->count * self->hdr->entry_size; + + self->hdr = (ffs_hdr_t *)realloc(self->hdr, sizeof(*self->hdr) + size); + if (self->hdr == NULL) { + ERRNO(errno); + goto error; + } + memset(self->hdr->entries, 0, size); + + if (0 < self->hdr->entry_count) { + if (__entries_read(self->hdr, self->file, + self->offset + sizeof(*self->hdr)) < 0) + goto error; + } + + self->buf_count = 1; // default to 1 + + self->buf = malloc(self->buf_count * self->hdr->block_size); + if (self->hdr == NULL) { + ERRNO(errno); + goto error; + } + + if (setvbuf(self->file, self->buf, _IOFBF, + self->buf_count * self->hdr->block_size) != 0) { + ERRNO(errno); + goto error; + } + + if (false) { + error: + if (self != NULL) { + if (self->buf != NULL) + free(self->buf), self->buf = NULL; + if (self->hdr != NULL) + free(self->hdr), self->hdr = NULL; + + free(self), self = NULL; + } + } + + return self; +} + +ffs_t *__ffs_open(const char *path, off_t offset) +{ + assert(path != NULL); + + FILE *file = fopen(path, "r+"); + if (file == NULL) { + ERRNO(errno); + return NULL; + } + + ffs_t *self = __ffs_fopen(file, offset); + if (self != NULL) + self->path = strdup(path); + + return self; +} + +static int ffs_flush(ffs_t * self) +{ + assert(self != NULL); + + if (__hdr_write(self->hdr, self->file, self->offset) < 0) + return -1; + + if (fflush(self->file) != 0) { + ERRNO(errno); + return -1; + } + + if (fileno(self->file) != -1) { + if (fsync(fileno(self->file)) < 0) { + ERRNO(errno); + return -1; + } + } + + + self->dirty = false; + + return 0; +} + +int __ffs_info(ffs_t * self, int name, uint32_t *value) +{ + assert(self != NULL); + assert(value != NULL); + + switch (name) { + case FFS_INFO_MAGIC: + *value = self->hdr->magic; + break; + case FFS_INFO_VERSION: + *value = self->hdr->version; + break; + case FFS_INFO_ENTRY_SIZE: + *value = self->hdr->entry_size; + break; + case FFS_INFO_ENTRY_COUNT: + *value = self->hdr->entry_count; + break; + case FFS_INFO_BLOCK_SIZE: + *value = self->hdr->block_size; + break; + case FFS_INFO_BLOCK_COUNT: + *value = self->hdr->block_count; + break; + case FFS_INFO_BUFFER_COUNT: + *value = self->buf_count; + break; + case FFS_INFO_OFFSET: + *value = self->offset; + break; + default: + UNEXPECTED("'%d' invalid info field", name); + return -1; + } + + return 0; +} + +int __ffs_buffer(ffs_t * self, size_t size) +{ + assert(self != NULL); + + if (size == 0) + size = self->hdr->block_size; + + if (self->buf != NULL) { + free(self->buf); + self->buf_count = 0; + } + + self->buf_count = size / self->hdr->block_size; + size = self->buf_count * self->hdr->block_size; + + self->buf = malloc(size); + if (self->buf == NULL) { + ERRNO(errno); + return -1; + } + + if (setvbuf(self->file, self->buf, _IOFBF, size) < 0) { + ERRNO(errno); + return -1; + } + + return 0; +} + +int __ffs_fclose(ffs_t * self) +{ + if (self == NULL) + return 0; + + if (self->dirty == true) + if (ffs_flush(self) < 0) + return -1; + + if (self->buf != NULL) + free(self->buf), self->buf = NULL; + if (self->hdr != NULL) + free(self->hdr), self->hdr = NULL; + + memset(self, 0, sizeof(*self)); + free(self); + + return 0; +} + +int __ffs_close(ffs_t * self) +{ + if (unlikely(self == NULL)) + return 0; + + if (self->dirty == true) + if (ffs_flush(self) < 0) + return -1; + + if (self->path != NULL) + free(self->path), self->path = NULL; + if (self->file != NULL) + fclose(self->file), self->file = NULL; + + return __ffs_fclose(self); +} + +int __ffs_fsync(ffs_t * self) +{ + assert(self != NULL); + + if (fflush(self->file) < 0) { + ERRNO(errno); + return -1; + } + + if (fileno(self->file) != -1) + if (fsync(fileno(self->file)) < 0) + return -1; + + return 0; +} + +static ffs_entry_t *__add_entry_check(ffs_hdr_t * self, off_t offset, + size_t size) +{ + assert(self != NULL); + + int find_overlap(ffs_entry_t * entry) { + if (entry->type == FFS_TYPE_LOGICAL) + return 0; + + off_t entry_start = entry->base; + off_t entry_end = entry_start + entry->size - 1; + + off_t new_start = offset / self->block_size; + off_t new_end = new_start + (size / self->block_size) - 1; + + return !(new_start < entry_start && new_end < entry_start) && + !(entry_end < new_start && entry_end < new_end); + } + + return __iterate_entries(self, find_overlap); +} + +int __ffs_iterate_entries(ffs_t * self, int (*func) (ffs_entry_t *)) +{ + return __iterate_entries(self->hdr, func) != NULL; +} + +int __ffs_list_entries(ffs_t * self, const char * name, bool user, FILE * out) +{ + assert(self != NULL); + + if (out == NULL) + out = stdout; + + char full_name[4096]; + regex_t rx; + + int print_entry(ffs_entry_t * entry) + { + size_t offset = entry->base * self->hdr->block_size; + size_t size = entry->size * self->hdr->block_size; + + if (__ffs_entry_name(self, entry, full_name, + sizeof full_name) < 0) + return -1; + + if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH) + return 0; + + fprintf(stdout, "%3d [%08x-%08x:%8x] " + "[%c%c%c%c%c%c%c%c%c%c] %s\n", + entry->id, offset, offset+size-1, entry->actual, + entry->type == FFS_TYPE_LOGICAL ? 'l' : 'd', + /* reserved */ '-', '-', '-', '-', '-', '-', '-', + entry->flags & FFS_FLAGS_U_BOOT_ENV ? 'b' : '-', + entry->flags & FFS_FLAGS_PROTECTED ? 'p' : '-', + full_name); + + if (user == true) { + for (int i=0; i<FFS_USER_WORDS; i++) { + fprintf(stdout, "[%2d] %8x ", i, + entry->user.data[i]); + if ((i+1) % 4 == 0) + fprintf(stdout, "\n"); + } + } + + return 0; + } + + if (0 < self->count) { + if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) { + ERRNO(errno); + return-1; + } + + fprintf(out, "========================[ PARTITION TABLE 0x%llx " + "]=======================\n", self->offset); + fprintf(out, "vers:%04x size:%04x * blk:%06x blk(s):%06x * " + "entsz:%06x ent(s):%06x\n", + self->hdr->version, self->hdr->size, + self->hdr->block_size, self->hdr->block_count, + self->hdr->entry_size, self->hdr->entry_count); + fprintf(out, "------------------------------------------------" + "---------------------------\n"); + + (void)__iterate_entries(self->hdr, print_entry); + + fprintf(stdout, "\n"); + + regfree(&rx); + } + + return 0; +} + +int __ffs_entry_find(ffs_t *self, const char *path, ffs_entry_t *entry) +{ + assert(self != NULL); + assert(path != NULL); + + ffs_entry_t *__entry = __find_entry(self->hdr, path); + if (__entry != NULL && entry != NULL) + *entry = *__entry; + + return __entry != NULL; +} + +int __ffs_entry_find_parent(ffs_t *self, const char *path, ffs_entry_t *entry) +{ + assert(self != NULL); + assert(path != NULL); + + if (*path == '/') + path++; + + char __path[strlen(path) + 1]; + strcpy(__path, path); + char *parent_path = dirname(__path); + + int found = 0; + + if (strcmp(parent_path, ".") != 0) { + ffs_entry_t parent; + + found = __ffs_entry_find(self, parent_path, &parent); + + if (found && entry != NULL) + *entry = parent; + } + + return found; +} + +int __ffs_entry_name(ffs_t *self, ffs_entry_t *entry, char *name, size_t size) +{ + assert(self != NULL); + assert(entry != NULL); + + ffs_hdr_t *hdr = self->hdr; + + int __entry_name(ffs_entry_t *parent, char *name, size_t size) { + assert(parent != NULL); + assert(name != NULL); + + if (parent->pid != FFS_PID_TOPLEVEL) { + for (uint32_t i = 0; i < hdr->entry_count; i++) { + if (hdr->entries[i].id == parent->pid) { + __entry_name(hdr->entries + i, name, + size); + break; + } + } + } + + if (strlen(name) + strlen(parent->name) < size) + strcat(name, parent->name); + + if (parent->id != entry->id) { + if (strlen(name) + strlen("/") < size) + strcat(name, "/"); + } + + return 0; + } + + memset(name, 0, size); + + return __entry_name(entry, name, size); +} + +int __ffs_entry_add(ffs_t * self, const char *path, off_t offset, size_t size, + ffs_type_t type, uint32_t flags) +{ + assert(self != NULL); + assert(path != NULL); + + if (__ffs_entry_find(self, path, NULL) == true) { + UNEXPECTED("'%s' entry already exists", path); + return -1; + } + + ffs_entry_t parent = {.id = FFS_PID_TOPLEVEL }; + (void)__ffs_entry_find_parent(self, path, &parent); + + ffs_hdr_t *hdr = self->hdr; + + if (type != FFS_TYPE_LOGICAL) { + ffs_entry_t *overlap = __add_entry_check(hdr, offset, size); + if (overlap != NULL) { + UNEXPECTED("'%s' at offset %lld and size %d overlaps " + "'%s' at offset %d and size %d", + path, offset, size, overlap->name, + overlap->base * hdr->block_size, + overlap->size * hdr->block_size); + return -1; + } + } + + int find_empty(ffs_entry_t * empty) { + return empty->type == 0; + } + + ffs_entry_t *entry = __iterate_entries(hdr, find_empty); + if (entry == NULL) { + if (self->count <= hdr->entry_count) { + size_t new_size; + new_size = hdr->entry_size * + (self->count + FFS_ENTRY_EXTENT); + + self->hdr = (ffs_hdr_t *) realloc(self->hdr, + sizeof(*self->hdr) + + new_size); + assert(self->hdr != NULL); + + if (hdr != self->hdr) + hdr = self->hdr; + + memset(hdr->entries + self->count, 0, + FFS_ENTRY_EXTENT * hdr->entry_size); + + self->count += FFS_ENTRY_EXTENT; + } + + entry = hdr->entries + hdr->entry_count; + } + + uint32_t max_id = 0; + + int find_max_id(ffs_entry_t * max) { + if (max_id < max->id) + max_id = max->id; + return 0; + } + + (void)__iterate_entries(hdr, find_max_id); + + char name[strlen(path) + 1]; + strcpy(name, path); + strncpy(entry->name, basename(name), sizeof(entry->name)); + entry->id = max_id + 1; + entry->pid = parent.id; + entry->base = offset / hdr->block_size; + entry->size = size / hdr->block_size; + entry->type = type; + entry->flags = flags; + entry->checksum = 0; + + hdr->entry_count++; + + self->dirty = true; + + return 0; +} + +int __ffs_entry_delete(ffs_t * self, const char *path) +{ + assert(self != NULL); + assert(path != NULL); + + ffs_entry_t entry; + if (__ffs_entry_find(self, path, &entry) == false) { + UNEXPECTED("entry '%s' not found in table at offset '%llx'", + path, self->offset); + return -1; + } + + if (entry.type == FFS_TYPE_PARTITION) { + UNEXPECTED("'%s' cannot --delete partition type entries", path); + return -1; + } + + uint32_t children = 0; + + int find_children(ffs_entry_t * child) { + if (entry.id == child->pid) + children++; + return 0; + } + + ffs_hdr_t *hdr = self->hdr; + + (void)__iterate_entries(hdr, find_children); + + if (0 < children) { + UNEXPECTED("'%s' has '%d' children, --delete those first", + path, children); + return -1; + } + + int find_entry_id(ffs_entry_t * __entry) { + return entry.id == __entry->id; + } + + ffs_entry_t *entry_p = __iterate_entries(hdr, find_entry_id); + assert(entry_p != NULL); + + int start = entry_p - hdr->entries; + int count = hdr->entry_count - start; + + memmove(entry_p, entry_p + 1, hdr->entry_size * count); + + hdr->entry_count = max(0UL, hdr->entry_count - 1); + memset(hdr->entries + hdr->entry_count, 0, hdr->entry_size); + + self->dirty = true; + + return 0; +} + +int __ffs_entry_user_get(ffs_t *self, const char *path, uint32_t word, + uint32_t *value) +{ + assert(self != NULL); + assert(path != NULL); + assert(value != NULL); + + if (FFS_USER_WORDS <= word) { + UNEXPECTED("word '%d' outside range [0..%d]", + word, FFS_USER_WORDS - 1); + return -1; + } + + ffs_entry_t *entry = __find_entry(self->hdr, path); + if (entry == NULL) { + UNEXPECTED("entry '%s' not found in partition table at " + "offset '%llx'", path, self->offset); + return -1; + } + + *value = entry->user.data[word]; + + return 0; +} + +int __ffs_entry_user_put(ffs_t *self, const char *path, uint32_t word, + uint32_t value) +{ + assert(self != NULL); + assert(path != NULL); + + if (FFS_USER_WORDS <= word) { + UNEXPECTED("word '%d' outside range [0..%d]", + word, FFS_USER_WORDS - 1); + return -1; + } + + ffs_entry_t *entry = __find_entry(self->hdr, path); + if (entry == NULL) { + UNEXPECTED("entry '%s' not found in partition table at " + "offset '%llx'", path, self->offset); + return -1; + } + + entry->user.data[word] = value; + self->dirty = true; + + return 0; +} + +ssize_t __ffs_entry_hexdump(ffs_t * self, const char *path, FILE * out) +{ + assert(self != NULL); + assert(path != NULL); + + ffs_entry_t entry; + if (__ffs_entry_find(self, path, &entry) == false) { + UNEXPECTED("entry '%s' not found in table at offset '%llx'", + path, self->offset); + return -1; + } + + size_t size = entry.size * self->hdr->block_size; + if (entry.actual < size) + size = entry.actual; + + off_t offset = entry.base * self->hdr->block_size; + + if (fseeko(self->file, offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + ssize_t total = 0; + + size_t block_size = self->hdr->block_size; + char block[block_size]; + while (0 < size) { + size_t rc = fread(block, 1, min(block_size, size), + self->file); + if (rc <= 0) { + if (ferror(self->file)) { + ERRNO(errno); + return -1; + } + break; + } + + dump_memory(out, offset + total, block, rc); + + total += rc; + size -= rc; + } + + return total; +} + +ssize_t __ffs_entry_truncate(ffs_t * self, const char *path, size_t size) +{ + assert(self != NULL); + assert(path != NULL); + + ffs_entry_t * entry = __find_entry(self->hdr, path); + if (entry == NULL) { + UNEXPECTED("entry '%s' not found in partition table at " + "offset '%llx'", path, self->offset); + return -1; + } + + if ((entry->size * self->hdr->block_size) < size) { + errno = EFBIG; + ERRNO(errno); + return -1; + } else { + entry->actual = size; + self->dirty = true; + } + + return 0; +} + +ssize_t __ffs_entry_read(ffs_t * self, const char *path, void *buf, + off_t offset, size_t count) +{ + assert(self != NULL); + assert(path != NULL); + assert(buf != NULL); + + if (count == 0) + return 0; + + ffs_entry_t entry; + if (__ffs_entry_find(self, path, &entry) == false) { + UNEXPECTED("entry '%s' not found in partition table at " + "offset '%llx'", path, self->offset); + return -1; + } + + size_t entry_size = entry.size * self->hdr->block_size; + if (entry.actual < entry_size) + entry_size = entry.actual; + off_t entry_offset = entry.base * self->hdr->block_size; + + if (entry_size <= offset) + return 0; + else + count = min(count, (entry_offset + entry_size) - offset); + + ssize_t total = 0; + + if (fseeko(self->file, entry_offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + if (fseeko(self->file, offset, SEEK_CUR) != 0) { + ERRNO(errno); + return -1; + } + + while (0 < count) { + size_t rc = fread(buf + total, 1, count, self->file); + if (rc <= 0) { + if (ferror(self->file)) { + ERRNO(errno); + return -1; + } + break; + } + + total += rc; + count -= rc; + } + + return total; +} + +ssize_t __ffs_entry_write(ffs_t * self, const char *path, const void *buf, + off_t offset, size_t count) +{ + assert(self != NULL); + assert(path != NULL); + assert(buf != NULL); + + if (count == 0) + return 0; + + ffs_entry_t *entry = __find_entry(self->hdr, path); + if (entry == NULL) { + UNEXPECTED("entry '%s' not found in partition table at " + "offset '%llx'", path, self->offset); + return -1; + } + + size_t entry_size = entry->size * self->hdr->block_size; + off_t entry_offset = entry->base * self->hdr->block_size; + + if (entry_size <= offset) + return 0; + else + count = min(count, (entry_offset + entry_size) - offset); + + ssize_t total = 0; + + if (fseeko(self->file, entry_offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + if (fseeko(self->file, offset, SEEK_CUR) != 0) { + ERRNO(errno); + return -1; + } + + while (0 < count) { + size_t rc = fwrite(buf + total, 1, count, self->file); + if (rc <= 0) { + if (ferror(self->file)) { + ERRNO(errno); + return -1; + } + break; + } + total += rc; + count -= rc; + } + + fflush(self->file); + + if (entry->actual < (uint32_t) total) { + entry->actual = (uint32_t) total; + self->dirty = true; + } + + return total; +} + +#if 0 +ssize_t __ffs_entry_copy(ffs_t *self, ffs_t *in, const char *path) +{ + assert(self != NULL); + assert(in != NULL); + assert(path != NULL); + + if (unlikely(*path == '\0')) + return 0; + + ffs_entry_t *src = __find_entry(in->hdr, path); + if (src == NULL) { + UNEXPECTED("entry '%s' not found in table at offset '%llx'", + path, in->offset); + return -1; + } + + ffs_entry_t *dest = __find_entry(self->hdr, path); + if (dest == NULL) { + UNEXPECTED("entry '%s' not found in table at offset '%llx'", + path, self->offset); + return -1; + } + + if (src->base != dest->base) { + UNEXPECTED("partition '%s' offsets differ '%x' != '%x'", + path, src->base, dest->base); + return -1; + } + + if (src->size != dest->size) { + UNEXPECTED("partition '%s' sizes differ '%x' != '%x'", + path, src->size, dest->size); + return -1; + } + + size_t block_size = self->hdr->block_size; + off_t src_offset = src->base * in->hdr->block_size; + size_t src_actual = src->actual; + off_t dest_offset = dest->base * self->hdr->block_size; + + if (fseeko(in->file, src_offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + if (fseeko(self->file, dest_offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + ssize_t total = 0; + char block[block_size]; + + while (0 < src_actual) { + size_t count = min(src_actual, block_size); + + size_t rc = fread(block, 1, count, in->file); + if (rc <= 0 && ferror(in->file)) { + ERRNO(errno); + return -1; + } + + rc = fwrite(block, 1, rc, self->file); + if (rc <= 0 && ferror(self->file)) { + ERRNO(errno); + return -1; + } + + total += rc; + src_actual -= rc; + } + + if (dest->actual != (uint32_t)total) { + dest->actual = (uint32_t) total; + self->dirty = true; + } + + return total; +} + +ssize_t __ffs_entry_compare(ffs_t * self, ffs_t * in, const char *path) +{ + assert(self != NULL); + assert(in != NULL); + assert(path != NULL); + + if (unlikely(*path == '\0')) + return 0; + + ffs_entry_t *src = __find_entry(in->hdr, path); + if (src == NULL) { + UNEXPECTED("entry '%s' not found in table at offset '%llx'", + path, in->offset); + return -1; + } + + ffs_entry_t *dest = __find_entry(self->hdr, path); + if (dest == NULL) { + UNEXPECTED("entry '%s' not found in table at offset '%llx'", + path, self->offset); + return -1; + } + + if (src->base != dest->base) { + UNEXPECTED("partition '%s' offsets differ '%x' != '%x'", + path, src->base, dest->base); + return -1; + } + + if (src->size != dest->size) { + UNEXPECTED("partition '%s' sizes differ '%x' != '%x'", + path, src->size, dest->size); + return -1; + } + + if (src->actual != dest->actual) { + UNEXPECTED("partition '%s' actual sizes differ '%x' != '%x'", + path, src->actual, dest->actual); + return -1; + } + + off_t offset = src->base * self->hdr->block_size; + size_t actual = src->actual; + + if (fseeko(in->file, offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + if (fseeko(self->file, offset, SEEK_SET) != 0) { + ERRNO(errno); + return -1; + } + + ssize_t total = 0; + size_t size = 256; + char __src[size], __dest[size]; + + while (0 < actual) { + size = min(actual, size); + + size_t rc = fread(__src, 1, size, in->file); + if (rc <= 0 && ferror(in->file)) { + ERRNO(errno); + return -1; + } + + rc = fread(__dest, 1, size, self->file); + if (rc <= 0 && ferror(self->file)) { + ERRNO(errno); + return -1; + } + + if (memcmp(__src, __dest, size) != 0) { + printf("==========> '%s'\n", self->path); + dump_memory(stdout, offset + total, __dest, size); + + printf("==========> '%s'\n", in->path); + dump_memory(stdout, offset + total, __src, size); + + break; + } + + actual -= size; + total += size; + } + + return total; +} +#endif + +int __ffs_entry_list(ffs_t * self, ffs_entry_t ** list) +{ + assert(self != NULL); + assert(list != NULL); + + size_t size = 0, count = 0; + *list = NULL; + + int name_list(ffs_entry_t * entry) { + if (size <= count) { + size += 10; + + *list = realloc(*list, size * sizeof(**list)); + if (*list == NULL) { + ERRNO(errno); + return -1; + } + } + + (*list)[count++] = *entry; + + return 0; + } + + if (__ffs_iterate_entries(self, name_list) != 0) { + if (*list != NULL) + free(*list), *list = NULL; + count = 0; + return -1; + } + + return count; +} + +/* ============================================================ */ diff --git a/ffs/src/libffs2.c b/ffs/src/libffs2.c new file mode 100644 index 0000000..0c83cf0 --- /dev/null +++ b/ffs/src/libffs2.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) International Business Machines Corp., 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * File: libffs2.c + * Author: Shaun Wetzstein <shaun@us.ibm.com> + * Descr: FFS IO interface + * Note: + * Date: 05/07/12 + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <endian.h> +#include <libgen.h> + +#include "libffs2.h" + +#include <clib/assert.h> +#include <clib/builtin.h> +#include <clib/checksum.h> +#include <clib/misc.h> +#include <clib/err.h> +#include <clib/raii.h> + +#define FFS_ERRSTR_MAX 1024 + +struct ffs_error { + int errnum; + char errstr[FFS_ERRSTR_MAX]; +}; + +typedef struct ffs_error ffs_error_t; + +static ffs_error_t __error; + +/* ============================================================ */ + +extern void ffs_errclr(void) +{ + __error.errnum = __error.errstr[0] = 0; +} + +extern int ffs_errnum(void) +{ + return __error.errnum; +} + +extern const char *ffs_errstr(void) +{ + return __error.errnum ? __error.errstr : NULL; +} + +int ffs_check(const char *path, off_t offset) +{ + RAII(FILE*, file, fopen(path, "r"), fclose); + if (file == NULL) { + __error.errnum = -1; + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : %s (errno=%d)\n", + program_invocation_short_name, "errno", + __FILE__, __LINE__, strerror(errno), errno); + + return -1; + } + + int rc = __ffs_fcheck(file, offset); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + // __ffs_check will return FFS_CHECK_* const's + } + + return rc; +} + +ffs_t *ffs_create(const char *path, off_t offset, uint32_t block_size, + uint32_t block_count) +{ + ffs_t *self = __ffs_create(path, offset, block_size, block_count); + if (self == NULL) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + } + + return self; +} + +ffs_t *ffs_open(const char *path, off_t offset) +{ + FILE * file = fopen(path, "r+"); + if (file == NULL) { + __error.errnum = -1; + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : %s (errno=%d)\n", + program_invocation_short_name, "errno", + __FILE__, __LINE__, strerror(errno), errno); + + return NULL; + } + + ffs_t *self = __ffs_fopen(file, offset); + if (self == NULL) { + fclose(file); + + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + } + + return self; +} + +int ffs_info(ffs_t *self, int name, uint32_t *value) +{ + int rc = __ffs_info(self, name, value); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_close(ffs_t * self) +{ + int rc = __ffs_close(self); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_fsync(ffs_t * self) +{ + int rc = __ffs_fsync(self); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_list_entries(ffs_t * self, FILE * out) +{ + int rc = __ffs_list_entries(self, ".*", true, out); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_iterate_entries(ffs_t * self, int (*func) (ffs_entry_t *)) +{ + int rc = __ffs_iterate_entries(self, func); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_entry_find(ffs_t * self, const char *path, ffs_entry_t * entry) +{ + int rc = __ffs_entry_find(self, path, entry); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_entry_find_parent(ffs_t * self, const char *path, ffs_entry_t * entry) +{ + int rc = __ffs_entry_find_parent(self, path, entry); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_entry_add(ffs_t * self, const char *path, off_t offset, size_t size, + ffs_type_t type, uint32_t flags) +{ + int rc = __ffs_entry_add(self, path, offset, size, type, flags); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_entry_delete(ffs_t * self, const char *path) +{ + int rc = __ffs_entry_delete(self, path); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_entry_user_get(ffs_t * self, const char *path, uint32_t word, + uint32_t * value) +{ + int rc = __ffs_entry_user_get(self, path, word, value); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +int ffs_entry_user_put(ffs_t * self, const char *path, uint32_t word, + uint32_t value) +{ + int rc = __ffs_entry_user_put(self, path, word, value); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +ssize_t ffs_entry_hexdump(ffs_t * self, const char *path, FILE * out) +{ + ssize_t rc = __ffs_entry_hexdump(self, path, out); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +ssize_t ffs_entry_truncate(ffs_t * self, const char *path, off_t offset, + uint8_t pad __unused__) +{ + return ffs_entry_truncate_no_pad(self, path, offset); +} + +ssize_t ffs_entry_truncate_no_pad(ffs_t * self, const char *path, off_t offset) +{ + ssize_t rc = __ffs_entry_truncate(self, path, offset); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +ssize_t ffs_entry_read(ffs_t * self, const char *path, void *buf, off_t offset, + size_t count) +{ + ssize_t rc = __ffs_entry_read(self, path, buf, offset, count); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +ssize_t ffs_entry_write(ffs_t * self, const char *path, const void *buf, + off_t offset, size_t count) +{ + ssize_t rc = __ffs_entry_write(self, path, buf, offset, count); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +ssize_t ffs_entry_list(ffs_t * self, ffs_entry_t ** list) +{ + ssize_t rc = __ffs_entry_list(self, list); + if (rc < 0) { + err_t *err = err_get(); + assert(err != NULL); + + __error.errnum = err_code(err); + snprintf(__error.errstr, sizeof __error.errstr, + "%s: %s : %s(%d) : (code=%d) %.*s\n", + program_invocation_short_name, + err_type_name(err), err_file(err), err_line(err), + err_code(err), err_size(err), (char *)err_data(err)); + + rc = -1; + } + + return rc; +} + +/* ============================================================ */ |