diff --git a/common/environment.c b/common/environment.c index 695baf745..19fb0273b 100644 --- a/common/environment.c +++ b/common/environment.c @@ -218,79 +218,53 @@ out1: } EXPORT_SYMBOL(envfs_save); -/** - * Restore the last environment into the current one - * @param[in] filename from where to restore - * @param[in] dir where to store the last content - * @return 0 on success, anything else in case of failure - * - * Note: This function will also be used on the host! See note in the header - * of this file. - */ -int envfs_load(const char *filename, const char *dir, unsigned flags) +static int envfs_check_super(struct envfs_super *super, size_t *size) +{ + if (ENVFS_32(super->magic) != ENVFS_MAGIC) { + printf("envfs: wrong magic\n"); + return -EIO; + } + + if (crc32(0, super, sizeof(*super) - 4) != ENVFS_32(super->sb_crc)) { + printf("wrong crc on env superblock\n"); + return -EIO; + } + + if (super->major < ENVFS_MAJOR) + printf("envfs version %d.%d loaded into %d.%d\n", + super->major, super->minor, + ENVFS_MAJOR, ENVFS_MINOR); + + *size = ENVFS_32(super->size); + + return 0; +} + +static int envfs_check_data(struct envfs_super *super, void *buf, size_t size) +{ + uint32_t crc; + + crc = crc32(0, buf, size); + if (crc != ENVFS_32(super->crc)) { + printf("wrong crc on env\n"); + return -EIO; + } + + return 0; +} + +static int envfs_load_data(void *buf, size_t size, const char *dir, unsigned flags) { struct envfs_super super; - void *buf = NULL, *buf_free = NULL; - int envfd; int fd, ret = 0; char *str, *tmp; int headerlen_full; - unsigned long size; /* for envfs < 1.0 */ struct envfs_inode_end inode_end_dummy; inode_end_dummy.mode = ENVFS_32(S_IRWXU | S_IRWXG | S_IRWXO); inode_end_dummy.magic = ENVFS_32(ENVFS_INODE_END_MAGIC); - envfd = open(filename, O_RDONLY); - if (envfd < 0) { - printf("Open %s %s\n", filename, errno_str()); - return -1; - } - - /* read superblock */ - ret = read(envfd, &super, sizeof(struct envfs_super)); - if ( ret < sizeof(struct envfs_super)) { - perror("read"); - ret = -errno; - goto out; - } - - if ( ENVFS_32(super.magic) != ENVFS_MAGIC) { - printf("envfs: wrong magic on %s\n", filename); - ret = -EIO; - goto out; - } - - if (crc32(0, (unsigned char *)&super, sizeof(struct envfs_super) - 4) - != ENVFS_32(super.sb_crc)) { - printf("wrong crc on env superblock\n"); - ret = -EIO; - goto out; - } - - size = ENVFS_32(super.size); - buf = xmalloc(size); - buf_free = buf; - ret = read(envfd, buf, size); - if (ret < size) { - perror("read"); - ret = -errno; - goto out; - } - - if (crc32(0, (unsigned char *)buf, size) - != ENVFS_32(super.crc)) { - printf("wrong crc on env\n"); - ret = -EIO; - goto out; - } - - if (super.major < ENVFS_MAJOR) - printf("envfs version %d.%d loaded into %d.%d\n", - super.major, super.minor, - ENVFS_MAJOR, ENVFS_MINOR); - while (size) { struct envfs_inode *inode; struct envfs_inode_end *inode_end; @@ -300,7 +274,7 @@ int envfs_load(const char *filename, const char *dir, unsigned flags) buf += sizeof(struct envfs_inode); if (ENVFS_32(inode->magic) != ENVFS_INODE_MAGIC) { - printf("envfs: wrong magic on %s\n", filename); + printf("envfs: wrong magic\n"); ret = -EIO; goto out; } @@ -324,7 +298,7 @@ int envfs_load(const char *filename, const char *dir, unsigned flags) buf += headerlen_full; if (ENVFS_32(inode_end->magic) != ENVFS_INODE_END_MAGIC) { - printf("envfs: wrong inode_end_magic on %s\n", filename); + printf("envfs: wrong inode_end_magic\n"); ret = -EIO; goto out; } @@ -368,11 +342,88 @@ skip: sizeof(struct envfs_inode); } + ret = 0; +out: + return ret; +} + +int envfs_load_from_buf(void *buf, int len, const char *dir, unsigned flags) +{ + int ret; + size_t size; + struct envfs_super *super = buf; + + buf = super + 1; + + ret = envfs_check_super(super, &size); + if (ret) + return ret; + + ret = envfs_check_data(super, buf, size); + if (ret) + return ret; + + ret = envfs_load_data(buf, size, dir, flags); + + return ret; +} + +/** + * Restore the last environment into the current one + * @param[in] filename from where to restore + * @param[in] dir where to store the last content + * @return 0 on success, anything else in case of failure + * + * Note: This function will also be used on the host! See note in the header + * of this file. + */ +int envfs_load(const char *filename, const char *dir, unsigned flags) +{ + struct envfs_super super; + void *buf = NULL; + int envfd; + int ret = 0; + size_t size; + + envfd = open(filename, O_RDONLY); + if (envfd < 0) { + printf("Open %s %s\n", filename, errno_str()); + return -1; + } + + /* read superblock */ + ret = read(envfd, &super, sizeof(struct envfs_super)); + if ( ret < sizeof(struct envfs_super)) { + perror("read"); + ret = -errno; + goto out; + } + + ret = envfs_check_super(&super, &size); + if (ret) + goto out; + + buf = xmalloc(size); + ret = read(envfd, buf, size); + if (ret < size) { + perror("read"); + ret = -errno; + goto out; + } + + ret = envfs_check_data(&super, buf, size); + if (ret) + goto out; + + ret = envfs_load_data(buf, size, dir, flags); + if (ret) + goto out; + ret = 0; out: close(envfd); - if (buf_free) - free(buf_free); + free(buf); + return ret; } diff --git a/include/envfs.h b/include/envfs.h index 94d1353ca..b63683c04 100644 --- a/include/envfs.h +++ b/include/envfs.h @@ -92,6 +92,7 @@ struct envfs_super { #define ENV_FLAG_NO_OVERWRITE (1 << 0) int envfs_load(const char *filename, const char *dirname, unsigned flags); int envfs_save(const char *filename, const char *dirname); +int envfs_load_from_buf(void *buf, int len, const char *dir, unsigned flags); /* defaults to /dev/env0 */ #ifdef CONFIG_ENV_HANDLING