diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-09-25 12:58:52 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2007-09-25 12:58:52 +0200 |
commit | 913691eccd13c1509470eb8b059aa0beecc6d8d8 (patch) | |
tree | 114ef2d910ae37d450031a1b1e5814768d5e8dd7 | |
parent | fd4cc5d0d370c4cf10a3a8d3884ea69cbd04305b (diff) | |
download | barebox-913691eccd13c1509470eb8b059aa0beecc6d8d8.tar.gz barebox-913691eccd13c1509470eb8b059aa0beecc6d8d8.tar.xz |
add directory handling for environment
-rw-r--r-- | commands/environment.c | 191 | ||||
-rw-r--r-- | common/Makefile | 2 | ||||
-rw-r--r-- | include/envfs.h | 10 | ||||
-rw-r--r-- | scripts/ubootenv.c | 69 |
4 files changed, 202 insertions, 70 deletions
diff --git a/commands/environment.c b/commands/environment.c index 084c78cc21..2f211d1b0d 100644 --- a/commands/environment.c +++ b/commands/environment.c @@ -31,21 +31,63 @@ #include <linux/stat.h> #include <envfs.h> #include <xfuncs.h> +#include <libbb.h> +#include <libgen.h> #endif -int envfs_save(char *filename, char *dirname) +struct action_data { + int fd; + const char *base; +}; + +static int file_save_action(const char *filename, struct stat *statbuf, + void *userdata, int depth) { - DIR *dir; - struct dirent *d; - int malloc_size = 0; - struct stat s; - struct envfs_super super; - void *buf = NULL; - char tmp[PATH_MAX]; int isize; - int envfd; + struct action_data *data = userdata; struct envfs_inode *inode = NULL; int fd; + int namelen = strlen(filename) + 1 - strlen(data->base); + int namelen_full = (namelen + 3) & ~3; + + isize = namelen_full + ((statbuf->st_size + 3) & ~3) + sizeof(struct envfs_inode); + inode = xzalloc(isize); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror("open"); + goto out; + } + + if (read(fd, inode->data + namelen_full, statbuf->st_size) < statbuf->st_size) { + perror("read"); + goto out; + } + + close(fd); + inode->magic = ENVFS_INODE_MAGIC; + inode->namelen = namelen; + inode->size = namelen_full + statbuf->st_size; + + strcpy(inode->data, filename + strlen(data->base)); + + /* FIXME: calc crc */ + + if (write(data->fd, inode, isize) < isize) { + perror("write"); + goto out; + } +out: + free(inode); + return 1; +} + +int envfs_save(char *filename, char *dirname) +{ + struct envfs_super super; + int envfd; + struct envfs_inode inode; + struct action_data data; envfd = open(filename, O_WRONLY | O_CREAT); if (envfd < 0) { @@ -57,62 +99,20 @@ int envfs_save(char *filename, char *dirname) write(envfd, &super, sizeof(struct envfs_super)); - dir = opendir(dirname); - if (!dir) { - perror("opendir"); - close(envfd); - return errno; - } + data.fd = envfd; + data.base = dirname; - while ((d = readdir(dir))) { - sprintf(tmp, "%s/%s", dirname, d->d_name); - if (stat(tmp, &s)) { - perror("stat"); - goto out; - } - if (s.st_mode & S_IFDIR) - continue; + recursive_action(dirname, ACTION_RECURSE, file_save_action, + NULL, &data, 0); - isize = ((s.st_size + 3) & ~3) + sizeof(struct envfs_inode); - if (isize > malloc_size) { - if (buf) - free(buf); - inode = xmalloc(isize); - buf = inode; - malloc_size = isize; - } - fd = open(tmp, O_RDONLY); - if (fd < 0) { - perror("open"); - goto out; - } - if (read(fd, inode->data, s.st_size) < s.st_size) { - perror("read"); - goto out; - } - - close(fd); - inode->magic = ENVFS_INODE_MAGIC; - inode->size = s.st_size; - strcpy(inode->name, d->d_name); /* FIXME: strncpy */ - /* FIXME: calc crc */ - if (write(envfd, inode, isize) < isize) { - perror("write"); - goto out; - } - } - - memset(inode, 0, sizeof(struct envfs_inode)); - inode->magic = ENVFS_END_MAGIC; - if (write(envfd, inode, sizeof(struct envfs_inode)) < sizeof(struct envfs_inode)) { + memset(&inode, 0, sizeof(struct envfs_inode)); + inode.magic = ENVFS_END_MAGIC; + if (write(envfd, &inode, sizeof(struct envfs_inode)) < sizeof(struct envfs_inode)) { perror("write"); goto out; } out: - if (buf) - free(buf); close(envfd); - closedir(dir); return 0; } @@ -132,13 +132,14 @@ int do_saveenv(cmd_tbl_t *cmdtp, int argc, char *argv[]) else filename = argv[1]; - fd = open(filename, O_WRONLY); + fd = open(filename, O_WRONLY | O_CREAT); if (fd < 0) { printf("could not open %s: %s", filename, errno_str()); return 1; } ret = protect(fd, ~0, 0, 0); + /* ENOSYS is no error here, many devices do not need it */ if (ret && errno != -ENOSYS) { printf("could not unprotect %s: %s\n", filename, errno_str()); @@ -156,10 +157,13 @@ int do_saveenv(cmd_tbl_t *cmdtp, int argc, char *argv[]) } ret = envfs_save(filename, dirname); - if (ret) + if (ret) { printf("saveenv failed\n"); + goto out; + } ret = protect(fd, ~0, 0, 1); + /* ENOSYS is no error here, many devices do not need it */ if (ret && errno != -ENOSYS) { printf("could not protect %s: %s\n", filename, errno_str()); @@ -167,6 +171,8 @@ int do_saveenv(cmd_tbl_t *cmdtp, int argc, char *argv[]) return 1; } + ret = 0; +out: close(fd); return ret; } @@ -186,15 +192,62 @@ U_BOOT_CMD_START(saveenv) U_BOOT_CMD_END #endif /* __U_BOOT__ */ -int envfs_load(char *filename, char *dirname) +int mkdirp(const char *dir) +{ + char *s = strdup(dir); + char *path = s; + char c; + + do { + c = 0; + + /* Bypass leading non-'/'s and then subsequent '/'s. */ + while (*s) { + if (*s == '/') { + do { + ++s; + } while (*s == '/'); + c = *s; /* Save the current char */ + *s = 0; /* and replace it with nul. */ + break; + } + ++s; + } + + if (mkdir(path, 0777) < 0) { + + /* If we failed for any other reason than the directory + * already exists, output a diagnostic and return -1.*/ +#ifdef __U_BOOT__ + if (errno != -EEXIST) +#else + if (errno != EEXIST) +#endif + break; + } + if (!c) + goto out; + + /* Remove any inserted nul from the path (recursive mode). */ + *s = c; + + } while (1); + +out: + free(path); + return errno; +} + +int envfs_load(char *filename, char *dir) { int malloc_size = 0; struct envfs_super super; void *buf = NULL; - char tmp[PATH_MAX]; int envfd; struct envfs_inode inode; int fd, ret = 0; + char *str, *tmp; + int namelen_full; envfd = open(filename, O_RDONLY); if (envfd < 0) { @@ -242,17 +295,23 @@ int envfs_load(char *filename, char *dirname) perror("read"); goto out; } - sprintf(tmp, "%s/%s", dirname, inode.name); - fd = open(tmp, O_WRONLY | O_CREAT); + str = concat_path_file(dir, buf); + tmp = strdup(str); + mkdirp(dirname(tmp)); + free(tmp); + + fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644); + free(str); if (fd < 0) { perror("open"); ret = fd; goto out; } - ret = write(fd, buf, inode.size); - if (ret < inode.size) { + namelen_full = ((inode.namelen + 3) & ~3); + ret = write(fd, buf + namelen_full, inode.size - namelen_full); + if (ret < inode.size - namelen_full) { perror("write"); close(fd); goto out; diff --git a/common/Makefile b/common/Makefile index b0df09a7c9..638d38c35c 100644 --- a/common/Makefile +++ b/common/Makefile @@ -14,7 +14,7 @@ obj-y += misc.o obj-y += memsize.o ifdef CONFIG_DEFAULT_ENVIRONMENT_PATH -include/uboot_default_env.h: $(shell ls $(CONFIG_DEFAULT_ENVIRONMENT_PATH)/*) +include/uboot_default_env.h: $(shell find $(CONFIG_DEFAULT_ENVIRONMENT_PATH) -type f) $(Q)scripts/ubootenv -s $(CONFIG_DEFAULT_ENVIRONMENT_PATH) uboot_default_env $(Q)cat uboot_default_env | scripts/bin2c default_environment > $@ diff --git a/include/envfs.h b/include/envfs.h index b04c3b8b20..bc043c9bbb 100644 --- a/include/envfs.h +++ b/include/envfs.h @@ -10,8 +10,12 @@ struct envfs_inode { uint32_t magic; /* 0x67a8c78d */ uint32_t crc; /* crc for this inode and corresponding data */ uint32_t size; /* data size in bytes */ - char name[32]; - char data[0]; + uint32_t namelen; /* The length of the filename _including_ the trailing 0 */ + char data[0]; /* The filename (zero terminated) + padding to 4 byte boundary + * followed by the data for this inode. + * The next inode follows after the data + padding to 4 byte + * boundary. + */ }; /* @@ -21,7 +25,7 @@ struct envfs_super { uint32_t magic; /* 0x798fba79 - random number */ uint32_t priority; uint32_t flags; /* feature flags */ - uint32_t future; /* reserved for future use */ + uint32_t future; /* reserved for future use */ }; #if __BYTE_ORDER == __LITTLE_ENDIAN diff --git a/scripts/ubootenv.c b/scripts/ubootenv.c index eb62123faf..37f799c456 100644 --- a/scripts/ubootenv.c +++ b/scripts/ubootenv.c @@ -32,6 +32,7 @@ #include <stdlib.h> #include <string.h> #include <getopt.h> +#include <libgen.h> void *xmalloc(size_t size) { @@ -45,6 +46,74 @@ void *xmalloc(size_t size) return p; } +void *xzalloc(size_t size) +{ + void *p = xmalloc(size); + memset(p, 0, size); + return p; +} + +/* Find out if the last character of a string matches the one given. + * Don't underrun the buffer if the string length is 0. + */ +char* last_char_is(const char *s, int c) +{ + if (s && *s) { + size_t sz = strlen(s) - 1; + s += sz; + if ( (unsigned char)*s == c) + return (char*)s; + } + return NULL; +} + +enum { + ACTION_RECURSE = (1 << 0), + /* ACTION_FOLLOWLINKS = (1 << 1), - unused */ + ACTION_DEPTHFIRST = (1 << 2), + /*ACTION_REVERSE = (1 << 3), - unused */ +}; + +int recursive_action(const char *fileName, unsigned flags, + int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData, int depth), + int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData, int depth), + void* userData, const unsigned depth); + +#define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2]))) + +/* concatenate path and file name to new allocation buffer, + * not adding '/' if path name already has '/' + */ +char *concat_path_file(const char *path, const char *filename) +{ + char *lc, *str; + + if (!path) + path = ""; + lc = last_char_is(path, '/'); + while (*filename == '/') + filename++; + + str = xmalloc(strlen(path) + (lc==0 ? 1 : 0) + strlen(filename) + 1); + sprintf(str, "%s%s%s", path, (lc==NULL ? "/" : ""), filename); + + return str; +} + +/* + * This function make special for recursive actions with usage + * concat_path_file(path, filename) + * and skipping "." and ".." directory entries + */ + +char *concat_subpath_file(const char *path, const char *f) +{ + if (f && DOT_OR_DOTDOT(f)) + return NULL; + return concat_path_file(path, f); +} + +#include "../lib/recursive_action.c" #include "../include/envfs.h" #include "../commands/environment.c" |