From 2f17f1a22f112bbc1eaa179914f0e5069f2a5ba2 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 17 Aug 2012 00:48:35 +0800 Subject: [PATCH 01/19] fs: add readlink support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/fs.c | 37 +++++++++++++++++++++++++++++++++++++ include/fs.h | 5 +++++ 2 files changed, 42 insertions(+) diff --git a/fs/fs.c b/fs/fs.c index 0b376a544..6a855130a 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -890,6 +890,43 @@ int close(int fd) } EXPORT_SYMBOL(close); +int readlink(const char *pathname, char *buf, size_t bufsiz) +{ + struct fs_driver_d *fsdrv; + struct fs_device_d *fsdev; + char *p = normalise_path(pathname); + char *freep = p; + int ret; + + ret = path_check_prereq(pathname, S_IFLNK); + if (ret) + goto out; + + fsdev = get_fs_device_and_root_path(&p); + if (!fsdev) { + ret = -ENODEV; + goto out; + } + fsdrv = fsdev->driver; + + if (fsdrv->readlink) + ret = fsdrv->readlink(&fsdev->dev, p, buf, bufsiz); + else + ret = -ENOSYS; + + if (ret) + goto out; + +out: + free(freep); + + if (ret) + errno = -ret; + + return ret; +} +EXPORT_SYMBOL(readlink); + static int fs_match(struct device_d *dev, struct driver_d *drv) { return strcmp(dev->name, drv->name) ? -1 : 0; diff --git a/include/fs.h b/include/fs.h index c0b9f71fb..906d192a7 100644 --- a/include/fs.h +++ b/include/fs.h @@ -50,6 +50,9 @@ struct fs_driver_d { /* Truncate a file to given size */ int (*truncate)(struct device_d *dev, FILE *f, ulong size); + int (*readlink)(struct device_d *dev, const char *pathname, char *name, + size_t size); + int (*open)(struct device_d *dev, FILE *f, const char *pathname); int (*close)(struct device_d *dev, FILE *f); int (*read)(struct device_d *dev, FILE *f, void *buf, size_t size); @@ -124,6 +127,8 @@ DIR *opendir(const char *pathname); struct dirent *readdir(DIR *dir); int closedir(DIR *dir); +int readlink(const char *path, char *buf, size_t bufsiz); + int mount (const char *device, const char *fsname, const char *path); int umount(const char *pathname); From f4d850eb76df75b91acfc85cbe847325d66865db Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 4 Sep 2012 21:42:19 +0800 Subject: [PATCH 02/19] fs: fix rmdir with symlink Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/fs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/fs.c b/fs/fs.c index 6a855130a..914df5acb 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -1253,6 +1253,12 @@ int rmdir (const char *pathname) char *freep = p; int ret; + ret = path_check_prereq(pathname, S_IFLNK); + if (!ret) { + ret = -ENOTDIR; + goto out; + } + ret = path_check_prereq(pathname, S_IFDIR | S_UB_IS_EMPTY); if (ret) goto out; From 99684498ecf919cdf91378f278eb459cb6299b8d Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 22 Aug 2012 12:54:19 +0800 Subject: [PATCH 03/19] fs: rename stat to lstat as we implement lstat For compatibility put a inline on lstat for stat until we have the symlink support. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/fs.c | 10 +++++----- include/fs.h | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index 914df5acb..323b6c278 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -392,7 +392,7 @@ static int path_check_prereq(const char *path, unsigned int flags) unsigned int m; int ret = 0; - if (stat(path, &s)) { + if (lstat(path, &s)) { if (flags & S_UB_DOES_NOT_EXIST) goto out; ret = -ENOENT; @@ -434,7 +434,7 @@ static int parent_check_directory(const char *path) int ret; char *dir = dirname(xstrdup(path)); - ret = stat(dir, &s); + ret = lstat(dir, &s); free(dir); @@ -523,7 +523,7 @@ int open(const char *pathname, int flags, ...) char *freep = path; int ret; - exist_err = stat(path, &s); + exist_err = lstat(path, &s); if (!exist_err && S_ISDIR(s.st_mode)) { ret = -EISDIR; @@ -1167,7 +1167,7 @@ int closedir(DIR *dir) } EXPORT_SYMBOL(closedir); -int stat(const char *filename, struct stat *s) +int lstat(const char *filename, struct stat *s) { struct device_d *dev; struct fs_driver_d *fsdrv; @@ -1206,7 +1206,7 @@ out: return ret; } -EXPORT_SYMBOL(stat); +EXPORT_SYMBOL(lstat); int mkdir (const char *pathname, mode_t mode) { diff --git a/include/fs.h b/include/fs.h index 906d192a7..98210cfa9 100644 --- a/include/fs.h +++ b/include/fs.h @@ -104,7 +104,11 @@ int creat(const char *pathname, mode_t mode); int unlink(const char *pathname); int close(int fd); int flush(int fd); -int stat(const char *filename, struct stat *s); +int lstat(const char *filename, struct stat *s); +static inline int stat(const char *filename, struct stat *s) +{ + return lstat(filename, s); +} int read(int fd, void *buf, size_t count); int ioctl(int fd, int request, void *buf); ssize_t write(int fd, const void *buf, size_t count); From 65d4f485eb53e18d2832260ce4e56799e54fc2da Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 21 Aug 2012 17:21:33 +0800 Subject: [PATCH 04/19] fs: add symlink support Limit it's support to existing file only Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/fs.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 3 +++ 2 files changed, 54 insertions(+) diff --git a/fs/fs.c b/fs/fs.c index 323b6c278..f46c60637 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -927,6 +927,57 @@ out: } EXPORT_SYMBOL(readlink); +int symlink(const char *pathname, const char *newpath) +{ + struct fs_driver_d *fsdrv; + struct fs_device_d *fsdev; + char *p; + char *freep = normalise_path(pathname); + int ret; + struct stat s; + + if (!freep) + return -ENOMEM; + + if (!stat(freep, &s) && S_ISDIR(s.st_mode)) { + ret = -ENOSYS; + goto out; + } + + free(freep); + freep = p = normalise_path(newpath); + + if (!p) + return -ENOMEM; + + ret = lstat(p, &s); + if (!ret) { + ret = -EEXIST; + goto out; + } + + fsdev = get_fs_device_and_root_path(&p); + if (!fsdev) { + ret = -ENODEV; + goto out; + } + fsdrv = fsdev->driver; + + if (fsdrv->symlink) { + ret = fsdrv->symlink(&fsdev->dev, pathname, p); + } else { + ret = -EPERM; + } + +out: + free(freep); + if (ret) + errno = -ret; + + return ret; +} +EXPORT_SYMBOL(symlink); + static int fs_match(struct device_d *dev, struct driver_d *drv) { return strcmp(dev->name, drv->name) ? -1 : 0; diff --git a/include/fs.h b/include/fs.h index 98210cfa9..d96de0e89 100644 --- a/include/fs.h +++ b/include/fs.h @@ -50,6 +50,8 @@ struct fs_driver_d { /* Truncate a file to given size */ int (*truncate)(struct device_d *dev, FILE *f, ulong size); + int (*symlink)(struct device_d *dev, const char *pathname, + const char *newpath); int (*readlink)(struct device_d *dev, const char *pathname, char *name, size_t size); @@ -131,6 +133,7 @@ DIR *opendir(const char *pathname); struct dirent *readdir(DIR *dir); int closedir(DIR *dir); +int symlink(const char *pathname, const char *newpath); int readlink(const char *path, char *buf, size_t bufsiz); int mount (const char *device, const char *fsname, const char *path); From 2d7ac4aa33e1fcef8319ca7a0ae587f468fa26dd Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 22 Aug 2012 18:54:50 +0800 Subject: [PATCH 05/19] fs: implement stat stat() stats the file pointed to by path and fills in buf. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/fs.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 6 +-- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index f46c60637..dfe571af2 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -111,6 +112,61 @@ static int init_cwd(void) postcore_initcall(init_cwd); +char *normalise_link(const char *pathname, const char *symlink) +{ + const char *buf = symlink; + char *path_free, *path; + char *absolute_path; + int point = 0; + int dir = 1; + int len; + + if (symlink[0] == '/') + return strdup(symlink); + + while (*buf == '.' || *buf == '/') { + if (*buf == '.') { + point++; + } else if (*buf == '/') { + point = 0; + dir++; + } + if (point > 2) { + buf -= 2; + break; + } + buf++; + } + + path = path_free = strdup(pathname); + if (!path) + return NULL; + + while(dir) { + path = dirname(path); + dir--; + } + + len = strlen(buf) + strlen(path) + 1; + if (buf[0] != '/') + len++; + + absolute_path = calloc(sizeof(char), len); + + if (!absolute_path) + goto out; + + strcat(absolute_path, path); + if (buf[0] != '/') + strcat(absolute_path, "/"); + strcat(absolute_path, buf); + +out: + free(path_free); + + return absolute_path; +} + char *normalise_path(const char *pathname) { char *path = xzalloc(strlen(pathname) + strlen(cwd) + 2); @@ -512,6 +568,42 @@ out: } EXPORT_SYMBOL(unlink); +static char *realfile(const char *pathname, struct stat *s) +{ + char *path = normalise_path(pathname); + int ret; + + ret = lstat(path, s); + if (ret) + goto out; + + if (S_ISLNK(s->st_mode)) { + char tmp[PATH_MAX]; + char *new_path; + + memset(tmp, 0, PATH_MAX); + + ret = readlink(path, tmp, PATH_MAX - 1); + if (ret < 0) + goto out; + + new_path = normalise_link(path, tmp); + free(path); + if (!new_path) + return ERR_PTR(-ENOMEM); + path = new_path; + + ret = lstat(path, s); + } + + if (!ret) + return path; + +out: + free(path); + return ERR_PTR(ret); +} + int open(const char *pathname, int flags, ...) { struct fs_device_d *fsdev; @@ -1218,6 +1310,19 @@ int closedir(DIR *dir) } EXPORT_SYMBOL(closedir); +int stat(const char *filename, struct stat *s) +{ + char *f; + + f = realfile(filename, s); + if (IS_ERR(f)) + return PTR_ERR(f); + + free(f); + return 0; +} +EXPORT_SYMBOL(stat); + int lstat(const char *filename, struct stat *s) { struct device_d *dev; diff --git a/include/fs.h b/include/fs.h index d96de0e89..07976d279 100644 --- a/include/fs.h +++ b/include/fs.h @@ -107,10 +107,7 @@ int unlink(const char *pathname); int close(int fd); int flush(int fd); int lstat(const char *filename, struct stat *s); -static inline int stat(const char *filename, struct stat *s) -{ - return lstat(filename, s); -} +int stat(const char *filename, struct stat *s); int read(int fd, void *buf, size_t count); int ioctl(int fd, int request, void *buf); ssize_t write(int fd, const void *buf, size_t count); @@ -169,6 +166,7 @@ void *read_file(const char *filename, size_t *size); * of "..", "." and double slashes. The returned string must be freed wit free(). */ char *normalise_path(const char *path); +char *normalise_link(const char *pathname, const char* symlink); /* Register a new filesystem driver */ int register_fs_driver(struct fs_driver_d *fsdrv); From c3defd050428c14e956f56810b80cf7a1343f962 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 21 Aug 2012 18:12:34 +0800 Subject: [PATCH 06/19] fs: open: add symlink support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/fs.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/fs.c b/fs/fs.c index dfe571af2..5bfd7136a 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -609,13 +609,20 @@ int open(const char *pathname, int flags, ...) struct fs_device_d *fsdev; struct fs_driver_d *fsdrv; FILE *f; - int exist_err; + int exist_err = 0; struct stat s; - char *path = normalise_path(pathname); - char *freep = path; + char *path; + char *freep; int ret; - exist_err = lstat(path, &s); + path = realfile(pathname, &s); + + if (IS_ERR(path)) { + exist_err = PTR_ERR(path); + path = normalise_path(pathname); + } + + freep = path; if (!exist_err && S_ISDIR(s.st_mode)) { ret = -EISDIR; From 1483f45879c6676eebc3cd4298393aec2af105e6 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 17 Aug 2012 15:28:15 +0800 Subject: [PATCH 07/19] fs: introduce get_mounted_path to get the path where a file is mounted Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/fs.c | 9 +++++++++ include/fs.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/fs/fs.c b/fs/fs.c index 5bfd7136a..7e670ec02 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -243,6 +243,15 @@ static struct fs_device_d *get_fsdevice_by_path(const char *path) return fs_dev_root; } +char *get_mounted_path(const char *path) +{ + struct fs_device_d *fdev; + + fdev = get_fsdevice_by_path(path); + + return fdev->path; +} + static FILE files[MAX_FILES]; static FILE *get_file(void) diff --git a/include/fs.h b/include/fs.h index 07976d279..2c8b13b77 100644 --- a/include/fs.h +++ b/include/fs.h @@ -168,6 +168,8 @@ void *read_file(const char *filename, size_t *size); char *normalise_path(const char *path); char *normalise_link(const char *pathname, const char* symlink); +char *get_mounted_path(const char *path); + /* Register a new filesystem driver */ int register_fs_driver(struct fs_driver_d *fsdrv); From ad6c28ac41482e7d1caf9c7df7e7e48e3076995d Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 21 Aug 2012 17:23:48 +0800 Subject: [PATCH 08/19] ramfs: add symlink and readlink support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- fs/ramfs.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/fs/ramfs.c b/fs/ramfs.c index 91d06b8d3..8f3b93668 100644 --- a/fs/ramfs.c +++ b/fs/ramfs.c @@ -42,6 +42,7 @@ struct ramfs_inode { struct ramfs_inode *parent; struct ramfs_inode *next; struct ramfs_inode *child; + char *symlink; ulong mode; struct handle_d *handle; @@ -176,6 +177,7 @@ static void ramfs_put_inode(struct ramfs_inode *node) data = tmp; } + free(node->symlink); free(node->name); free(node); } @@ -212,18 +214,38 @@ static struct ramfs_inode* node_insert(struct ramfs_inode *parent_node, const ch /* ---------------------------------------------------------------*/ -static int ramfs_create(struct device_d *dev, const char *pathname, mode_t mode) +static int __ramfs_create(struct device_d *dev, const char *pathname, + mode_t mode, const char *symlink) { struct ramfs_priv *priv = dev->priv; struct ramfs_inode *node; char *file; + char *__symlink = NULL; node = rlookup_parent(priv, pathname, &file); - if (node) { - node_insert(node, file, mode); - return 0; + if (!node) + return -ENOENT; + + if (symlink) { + __symlink = strdup(symlink); + if (!__symlink) + return -ENOMEM; } - return -ENOENT; + + node = node_insert(node, file, mode); + if (!node) { + free(__symlink); + return -ENOMEM; + } + + node->symlink = __symlink; + + return 0; +} + +static int ramfs_create(struct device_d *dev, const char *pathname, mode_t mode) +{ + return __ramfs_create(dev, pathname, mode, NULL); } static int ramfs_unlink(struct device_d *dev, const char *pathname) @@ -532,12 +554,37 @@ static int ramfs_stat(struct device_d *dev, const char *filename, struct stat *s if (!node) return -ENOENT; - s->st_size = node->size; + s->st_size = node->symlink ? strlen(node->symlink) : node->size; s->st_mode = node->mode; return 0; } +static int ramfs_symlink(struct device_d *dev, const char *pathname, + const char *newpath) +{ + mode_t mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; + + return __ramfs_create(dev, newpath, mode, pathname); +} + +static int ramfs_readlink(struct device_d *dev, const char *pathname, + char *buf, size_t bufsiz) +{ + struct ramfs_priv *priv = dev->priv; + struct ramfs_inode *node = rlookup(priv, pathname); + int len; + + if (!node || !node->symlink) + return -ENOENT; + + len = min(bufsiz, strlen(node->symlink)); + + memcpy(buf, node->symlink, len); + + return 0; +} + static int ramfs_probe(struct device_d *dev) { struct ramfs_inode *n; @@ -584,6 +631,8 @@ static struct fs_driver_d ramfs_driver = { .readdir = ramfs_readdir, .closedir = ramfs_closedir, .stat = ramfs_stat, + .symlink = ramfs_symlink, + .readlink = ramfs_readlink, .flags = FS_DRIVER_NO_DEV, .drv = { .probe = ramfs_probe, From 0e22047a993ebdc900855cd752fd230b5b6a86e4 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 17 Aug 2012 00:49:00 +0800 Subject: [PATCH 09/19] nfs: add readlink support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- MAKEALL | 1 + fs/nfs.c | 86 ++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 59 insertions(+), 28 deletions(-) diff --git a/MAKEALL b/MAKEALL index 1ba4710de..056a4d054 100755 --- a/MAKEALL +++ b/MAKEALL @@ -264,3 +264,4 @@ then else do_build_target ${ARCH} $1 fi +exit $nb_errors diff --git a/fs/nfs.c b/fs/nfs.c index 79e667f48..4a880cd30 100644 --- a/fs/nfs.c +++ b/fs/nfs.c @@ -605,34 +605,6 @@ static int nfs_read_req(struct file_priv *priv, int offset, int readlen) return 0; } -#if 0 -static int nfs_readlink_reply(unsigned char *pkt, unsigned len) -{ - uint32_t *data; - char *path; - int rlen; -// int ret; - - data = (uint32_t *)(pkt + sizeof(struct rpc_reply)); - - data++; - - rlen = ntohl(net_read_uint32(data)); /* new path length */ - - data++; - path = (char *)data; - - if (*path != '/') { - strcat(nfs_path, "/"); - strncat(nfs_path, path, rlen); - } else { - memcpy(nfs_path, path, rlen); - nfs_path[rlen] = 0; - } - return 0; -} -#endif - static void nfs_handler(void *ctx, char *packet, unsigned len) { char *pkt = net_eth_to_udp_payload(packet); @@ -742,6 +714,63 @@ static struct file_priv *nfs_do_stat(struct device_d *dev, const char *filename, return priv; } +static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size) +{ + uint32_t data[1024]; + uint32_t *p; + int len; + int ret; + char *path; + uint32_t *filedata; + + p = &(data[0]); + p = rpc_add_credentials(p); + + memcpy(p, priv->filefh, NFS_FHSIZE); + p += (NFS_FHSIZE / 4); + + len = p - &(data[0]); + + ret = rpc_req(priv->npriv, PROG_NFS, NFS_READLINK, data, len); + if (ret) + return ret; + + filedata = nfs_packet + sizeof(struct rpc_reply); + filedata++; + + len = ntohl(net_read_uint32(filedata)); /* new path length */ + filedata++; + + path = (char *)filedata; + + if (len > size) + len = size; + + memcpy(buf, path, len); + + return 0; +} + +static int nfs_readlink(struct device_d *dev, const char *filename, + char *realname, size_t size) +{ + struct file_priv *priv; + int ret; + struct stat s; + + priv = nfs_do_stat(dev, filename, &s); + if (IS_ERR(priv)) + return PTR_ERR(priv); + + ret = nfs_readlink_req(priv, realname, size); + if (ret) { + nfs_do_close(priv); + return ret; + } + + return 0; +} + static int nfs_open(struct device_d *dev, FILE *file, const char *filename) { struct file_priv *priv; @@ -1039,6 +1068,7 @@ static struct fs_driver_d nfs_driver = { .rmdir = nfs_rmdir, .write = nfs_write, .truncate = nfs_truncate, + .readlink = nfs_readlink, .flags = 0, .drv = { .probe = nfs_probe, From f26472f2d1fe42e8d96fafae1077e5a67767a236 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Thu, 16 Aug 2012 21:36:42 +0800 Subject: [PATCH 10/19] test: add -L support to test if it's a symbolic link Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- commands/test.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/commands/test.c b/commands/test.c index 9ffa89252..18eeaab8c 100644 --- a/commands/test.c +++ b/commands/test.c @@ -43,6 +43,7 @@ typedef enum { OPT_DIRECTORY, OPT_FILE, OPT_EXISTS, + OPT_SYMBOLIC_LINK, OPT_MAX, } test_opts; @@ -62,6 +63,7 @@ static char *test_options[] = { [OPT_FILE] = "-f", [OPT_DIRECTORY] = "-d", [OPT_EXISTS] = "-e", + [OPT_SYMBOLIC_LINK] = "-L", }; static int parse_opt(const char *opt) @@ -140,9 +142,10 @@ static int do_test(int argc, char *argv[]) case OPT_FILE: case OPT_DIRECTORY: case OPT_EXISTS: + case OPT_SYMBOLIC_LINK: adv = 2; if (ap[1] && *ap[1] != ']' && strlen(ap[1])) { - expr = stat(ap[1], &statbuf); + expr = (opt == OPT_SYMBOLIC_LINK ? lstat : stat)(ap[1], &statbuf); if (expr < 0) { expr = 0; break; @@ -160,6 +163,10 @@ static int do_test(int argc, char *argv[]) expr = 1; break; } + if (opt == OPT_SYMBOLIC_LINK && S_ISLNK(statbuf.st_mode)) { + expr = 1; + break; + } } break; @@ -224,7 +231,7 @@ static const char *test_aliases[] = { "[", NULL}; static const __maybe_unused char cmd_test_help[] = "Usage: test [OPTIONS]\n" -"options: !, =, !=, -eq, -ne, -ge, -gt, -le, -lt, -o, -a, -z, -n, -d, -e, -f\n" +"options: !, =, !=, -eq, -ne, -ge, -gt, -le, -lt, -o, -a, -z, -n, -d, -e, -f, -L\n" "see 'man test' on your PC for more information.\n"; static const __maybe_unused char cmd_test_usage[] = "minimal test like /bin/sh"; From 69a4ea15dbd5c3f0beac0f6a034a7dd2f13ff383 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 17 Aug 2012 00:49:46 +0800 Subject: [PATCH 11/19] command: add readlink support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- commands/Kconfig | 6 ++++ commands/Makefile | 1 + commands/readlink.c | 80 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 commands/readlink.c diff --git a/commands/Kconfig b/commands/Kconfig index 92a815290..876f2f840 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -220,6 +220,12 @@ config CMD_DIRNAME Strip last component of file name and store the result in a environment variable +config CMD_READLINK + tristate + prompt "readlink" + help + read value of a symbolic link + endmenu menu "console " diff --git a/commands/Makefile b/commands/Makefile index e9157bfcc..ab6c7ea5c 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -72,3 +72,4 @@ obj-$(CONFIG_CMD_AUTOMOUNT) += automount.o obj-$(CONFIG_CMD_GLOBAL) += global.o obj-$(CONFIG_CMD_BASENAME) += basename.o obj-$(CONFIG_CMD_DIRNAME) += dirname.o +obj-$(CONFIG_CMD_READLINK) += readlink.o diff --git a/commands/readlink.c b/commands/readlink.c new file mode 100644 index 000000000..d2671e0f2 --- /dev/null +++ b/commands/readlink.c @@ -0,0 +1,80 @@ +/* + * readlink.c - read value of a symbolic link + * + * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +static int do_readlink(int argc, char *argv[]) +{ + char realname[PATH_MAX]; + int canonicalize = 0; + int opt; + + memset(realname, 0, PATH_MAX); + + while ((opt = getopt(argc, argv, "f")) > 0) { + switch (opt) { + case 'f': + canonicalize = 1; + break; + } + } + + if (argc < optind + 2) + return COMMAND_ERROR_USAGE; + + if (readlink(argv[optind], realname, PATH_MAX - 1) < 0) + goto err; + + if (canonicalize) { + char *buf = normalise_link(argv[optind], realname); + + if (!buf) + goto err; + setenv(argv[optind + 1], buf); + free(buf); + } else { + setenv(argv[optind + 1], realname); + } + + return 0; +err: + setenv(argv[optind + 1], ""); + return 1; +} + +BAREBOX_CMD_HELP_START(readlink) +BAREBOX_CMD_HELP_USAGE("readlink [-f] FILE REALNAME\n") +BAREBOX_CMD_HELP_SHORT("read value of a symbolic link and store into $REALNAME\n") +BAREBOX_CMD_HELP_SHORT("-f canonicalize by following first symlink"); +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(readlink) + .cmd = do_readlink, + .usage = "read value of a symbolic link", + BAREBOX_CMD_HELP(cmd_readlink_help) +BAREBOX_CMD_END From bf32bc1d9aa5d01c054eb9483f61dc453a522978 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 21 Aug 2012 17:22:08 +0800 Subject: [PATCH 12/19] command: add ln support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- commands/Kconfig | 4 ++++ commands/Makefile | 1 + commands/ln.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 commands/ln.c diff --git a/commands/Kconfig b/commands/Kconfig index 876f2f840..337f54505 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -57,6 +57,10 @@ config CMD_READLINE tristate prompt "readline" +config CMD_LN + tristate + prompt "ln" + config CMD_TRUE tristate default y diff --git a/commands/Makefile b/commands/Makefile index ab6c7ea5c..ccebd7f55 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -73,3 +73,4 @@ obj-$(CONFIG_CMD_GLOBAL) += global.o obj-$(CONFIG_CMD_BASENAME) += basename.o obj-$(CONFIG_CMD_DIRNAME) += dirname.o obj-$(CONFIG_CMD_READLINK) += readlink.o +obj-$(CONFIG_CMD_LN) += ln.o diff --git a/commands/ln.c b/commands/ln.c new file mode 100644 index 000000000..0237447ae --- /dev/null +++ b/commands/ln.c @@ -0,0 +1,51 @@ +/* + * ln.c - make links between files + * + * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +static int do_ln(int argc, char *argv[]) +{ + if (argc != 3) + return COMMAND_ERROR_USAGE; + + if (symlink(argv[1], argv[2]) < 0) { + perror("ln"); + return 1; + } + return 0; +} + +BAREBOX_CMD_HELP_START(ln) +BAREBOX_CMD_HELP_USAGE("ln SRC DEST\n") +BAREBOX_CMD_HELP_SHORT("symlink - make a new name for a file\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(ln) + .cmd = do_ln, + .usage = "symlink - make a new name for a file", + BAREBOX_CMD_HELP(cmd_ln_help) +BAREBOX_CMD_END From 0939b7c549f6c4175efffcf3a18efc1197e9a2b0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 22 Aug 2012 15:20:58 +0800 Subject: [PATCH 13/19] ls: add symlink support to -l barebox:/ ls -l /env/init.d/ drwxrwxrwx 0 . drwxrwxrwx 0 .. lrwxrwxrwx 11 net -> ../boot/net Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- commands/ls.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/commands/ls.c b/commands/ls.c index fbcbadcd0..d36ef578c 100644 --- a/commands/ls.c +++ b/commands/ls.c @@ -29,13 +29,24 @@ #include #include -static void ls_one(const char *path, struct stat *s) +static void ls_one(const char *path, const char* fullname, struct stat *s) { char modestr[11]; unsigned int namelen = strlen(path); mkmodestr(s->st_mode, modestr); - printf("%s %10llu %*.*s\n", modestr, s->st_size, namelen, namelen, path); + printf("%s %10llu %*.*s", modestr, s->st_size, namelen, namelen, path); + + if (S_ISLNK(s->st_mode)) { + char realname[PATH_MAX]; + + memset(realname, 0, PATH_MAX); + + if (readlink(fullname, realname, PATH_MAX - 1) >= 0) + printf(" -> %s", realname); + } + + puts("\n"); } int ls(const char *path, ulong flags) @@ -48,14 +59,14 @@ int ls(const char *path, ulong flags) string_list_init(&sl); - if (stat(path, &s)) + if (lstat(path, &s)) return -errno; if (flags & LS_SHOWARG && s.st_mode & S_IFDIR) printf("%s:\n", path); if (!(s.st_mode & S_IFDIR)) { - ls_one(path, &s); + ls_one(path, path, &s); return 0; } @@ -65,12 +76,12 @@ int ls(const char *path, ulong flags) while ((d = readdir(dir))) { sprintf(tmp, "%s/%s", path, d->d_name); - if (stat(tmp, &s)) + if (lstat(tmp, &s)) goto out; if (flags & LS_COLUMN) string_list_add_sorted(&sl, d->d_name); else - ls_one(d->d_name, &s); + ls_one(d->d_name, tmp, &s); } closedir(dir); @@ -97,7 +108,7 @@ int ls(const char *path, ulong flags) continue; sprintf(tmp, "%s/%s", path, d->d_name); - if (stat(tmp, &s)) + if (lstat(tmp, &s)) goto out; if (s.st_mode & S_IFDIR) { char *norm = normalise_path(tmp); @@ -146,7 +157,7 @@ static int do_ls(int argc, char *argv[]) /* first pass: all files */ while (o < argc) { - ret = stat(argv[o], &s); + ret = lstat(argv[o], &s); if (ret) { printf("%s: %s: %s\n", argv[0], argv[o], errno_str()); @@ -158,7 +169,7 @@ static int do_ls(int argc, char *argv[]) if (flags & LS_COLUMN) string_list_add_sorted(&sl, argv[o]); else - ls_one(argv[o], &s); + ls_one(argv[o], argv[o], &s); } o++; @@ -173,7 +184,7 @@ static int do_ls(int argc, char *argv[]) /* second pass: directories */ while (o < argc) { - ret = stat(argv[o], &s); + ret = lstat(argv[o], &s); if (ret) { o++; continue; From dccdc2ed8889a791bb5f8151286975ad8a94ec1f Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 17 Aug 2012 01:32:07 +0800 Subject: [PATCH 14/19] dirname: add -V option to return only path related to the mountpoint Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- commands/dirname.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/commands/dirname.c b/commands/dirname.c index cf1d0a022..f34d88d0f 100644 --- a/commands/dirname.c +++ b/commands/dirname.c @@ -24,20 +24,38 @@ #include #include #include +#include +#include static int do_dirname(int argc, char *argv[]) { - if (argc != 3) + int opt; + int path_fs = 0; + int len = 0; + + while ((opt = getopt(argc, argv, "V")) > 0) { + switch (opt) { + case 'V': + path_fs = 1; + break; + } + } + + if (argc < optind + 2) return COMMAND_ERROR_USAGE; - setenv(argv[2], dirname(argv[1])); + if (path_fs) + len = strlen(get_mounted_path(argv[optind])); + + setenv(argv[optind + 1], dirname(argv[optind]) + len); return 0; } BAREBOX_CMD_HELP_START(dirname) -BAREBOX_CMD_HELP_USAGE("dirname NAME DIRNAME\n") +BAREBOX_CMD_HELP_USAGE("dirname [-V] NAME DIRNAME\n") BAREBOX_CMD_HELP_SHORT("strip last componext of NAME and store into $DIRNAME\n") +BAREBOX_CMD_HELP_SHORT("-V return the path relative to the mountpoint.\n") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(dirname) From f7edad7cbf4560902083df5ecc912b2d3f91ba28 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 22 Aug 2012 12:53:00 +0800 Subject: [PATCH 15/19] recursive_action: add ACTION_FOLLOWLINKS support this is need to support symlink in envfs Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- include/libbb.h | 2 +- lib/recursive_action.c | 7 ++++++- scripts/bareboxenv.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 110e8ec39..47b2e0829 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -14,7 +14,7 @@ char* last_char_is(const char *s, int c); enum { ACTION_RECURSE = (1 << 0), - /* ACTION_FOLLOWLINKS = (1 << 1), - unused */ + ACTION_FOLLOWLINKS = (1 << 1), ACTION_DEPTHFIRST = (1 << 2), /*ACTION_REVERSE = (1 << 3), - unused */ }; diff --git a/lib/recursive_action.c b/lib/recursive_action.c index 1ef758df6..5bc2595db 100644 --- a/lib/recursive_action.c +++ b/lib/recursive_action.c @@ -54,14 +54,19 @@ int recursive_action(const char *fileName, const unsigned depth) { struct stat statbuf; + unsigned follow; int status; DIR *dir; struct dirent *next; if (!fileAction) fileAction = true_action; if (!dirAction) dirAction = true_action; - status = stat(fileName, &statbuf); + follow = ACTION_FOLLOWLINKS; + if (depth == 0) + follow = ACTION_FOLLOWLINKS; + follow &= flags; + status = (follow ? stat : lstat)(fileName, &statbuf); if (status < 0) { #ifdef DEBUG_RECURS_ACTION bb_error_msg("status=%d followLinks=%d TRUE=%d", diff --git a/scripts/bareboxenv.c b/scripts/bareboxenv.c index 866e345b9..f7f5351ca 100644 --- a/scripts/bareboxenv.c +++ b/scripts/bareboxenv.c @@ -73,7 +73,7 @@ char* last_char_is(const char *s, int c) enum { ACTION_RECURSE = (1 << 0), - /* ACTION_FOLLOWLINKS = (1 << 1), - unused */ + ACTION_FOLLOWLINKS = (1 << 1), ACTION_DEPTHFIRST = (1 << 2), /*ACTION_REVERSE = (1 << 3), - unused */ }; From ff3058e3bb5644803cdb7836bbfe11e8c5fbc5db Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 21 Aug 2012 20:47:58 +0800 Subject: [PATCH 16/19] envfs: introduce version major and minor they are store in the super block at byte 16th and 17th. set the verison at 0.1 Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- common/environment.c | 2 ++ include/envfs.h | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/common/environment.c b/common/environment.c index 52ce0de1d..8efed978f 100644 --- a/common/environment.c +++ b/common/environment.c @@ -125,6 +125,8 @@ int envfs_save(char *filename, char *dirname) super = (struct envfs_super *)buf; super->magic = ENVFS_32(ENVFS_MAGIC); + super->major = ENVFS_MAJOR; + super->minor = ENVFS_MINOR; super->size = ENVFS_32(size); /* second pass: copy files to buffer */ diff --git a/include/envfs.h b/include/envfs.h index ba976d6d1..c6df8c504 100644 --- a/include/envfs.h +++ b/include/envfs.h @@ -5,6 +5,9 @@ #include #endif +#define ENVFS_MAJOR 0 +#define ENVFS_MINOR 1 + #define ENVFS_MAGIC 0x798fba79 /* some random number */ #define ENVFS_INODE_MAGIC 0x67a8c78d #define ENVFS_END_MAGIC 0x6a87d6cd @@ -29,8 +32,10 @@ struct envfs_super { uint32_t priority; uint32_t crc; /* crc for the data */ uint32_t size; /* size of data */ + uint8_t major; /* major */ + uint8_t minor; /* minor */ + uint16_t future; /* reserved for future use */ uint32_t flags; /* feature flags */ - uint32_t future; /* reserved for future use */ uint32_t sb_crc; /* crc for the superblock */ }; From d3cbc615962c8e96f88d9e74645c5afb441431bb Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 21 Aug 2012 21:47:53 +0800 Subject: [PATCH 17/19] envfs: add support of variable inode size Introduce a struct envfs_inode_end with more data. Today this will just containt the file mode to be able to add the symlink support. But this is compatible with the previous envfs version as they will do not care about the extra as the previous version is just reading the filename and then consume the extra data without using them. Increase the envfs version to 1.0 Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- common/environment.c | 53 ++++++++++++++++++++++++++++++++++---------- include/envfs.h | 12 +++++++--- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/common/environment.c b/common/environment.c index 8efed978f..fc5c57e88 100644 --- a/common/environment.c +++ b/common/environment.c @@ -53,6 +53,7 @@ int file_size_action(const char *filename, struct stat *statbuf, data->writep += sizeof(struct envfs_inode); data->writep += PAD4(strlen(filename) + 1 - strlen(data->base)); + data->writep += sizeof(struct envfs_inode_end); data->writep += PAD4(statbuf->st_size); return 1; } @@ -62,6 +63,7 @@ int file_save_action(const char *filename, struct stat *statbuf, { struct action_data *data = userdata; struct envfs_inode *inode; + struct envfs_inode_end *inode_end; int fd; int namelen = strlen(filename) + 1 - strlen(data->base); @@ -70,12 +72,16 @@ int file_save_action(const char *filename, struct stat *statbuf, inode = (struct envfs_inode*)data->writep; inode->magic = ENVFS_32(ENVFS_INODE_MAGIC); - inode->namelen = ENVFS_32(namelen); + inode->headerlen = ENVFS_32(PAD4(namelen + sizeof(struct envfs_inode_end))); inode->size = ENVFS_32(statbuf->st_size); data->writep += sizeof(struct envfs_inode); strcpy(data->writep, filename + strlen(data->base)); data->writep += PAD4(namelen); + inode_end = (struct envfs_inode_end*)data->writep; + data->writep += sizeof(struct envfs_inode_end); + inode_end->magic = ENVFS_32(ENVFS_INODE_END_MAGIC); + inode_end->mode = ENVFS_32(S_IRWXU | S_IRWXG | S_IRWXO); fd = open(filename, O_RDONLY); if (fd < 0) { @@ -176,8 +182,13 @@ int envfs_load(char *filename, char *dir) int envfd; int fd, ret = 0; char *str, *tmp; - int namelen_full; + 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) { @@ -223,11 +234,18 @@ int envfs_load(char *filename, char *dir) 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; - uint32_t inode_size, inode_namelen; + struct envfs_inode_end *inode_end; + uint32_t inode_size, inode_headerlen, namelen; inode = (struct envfs_inode *)buf; + buf += sizeof(struct envfs_inode); if (ENVFS_32(inode->magic) != ENVFS_INODE_MAGIC) { printf("envfs: wrong magic on %s\n", filename); @@ -235,16 +253,30 @@ int envfs_load(char *filename, char *dir) goto out; } inode_size = ENVFS_32(inode->size); - inode_namelen = ENVFS_32(inode->namelen); + inode_headerlen = ENVFS_32(inode->headerlen); + namelen = strlen(inode->data) + 1; + if (super.major < 1) + inode_end = &inode_end_dummy; + else + inode_end = (struct envfs_inode_end *)(buf + PAD4(namelen)); - debug("loading %s size %d namelen %d\n", inode->data, - inode_size, inode_namelen); + debug("loading %s size %d namelen %d headerlen %d\n", inode->data, + inode_size, namelen, inode_headerlen); str = concat_path_file(dir, inode->data); tmp = strdup(str); make_directory(dirname(tmp)); free(tmp); + headerlen_full = PAD4(inode_headerlen); + buf += headerlen_full; + + if (ENVFS_32(inode_end->magic) != ENVFS_INODE_END_MAGIC) { + printf("envfs: wrong inode_end_magic on %s\n", filename); + ret = -EIO; + goto out; + } + fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644); free(str); if (fd < 0) { @@ -253,9 +285,7 @@ int envfs_load(char *filename, char *dir) goto out; } - namelen_full = PAD4(inode_namelen); - ret = write(fd, buf + namelen_full + sizeof(struct envfs_inode), - inode_size); + ret = write(fd, buf, inode_size); if (ret < inode_size) { perror("write"); ret = -errno; @@ -264,9 +294,8 @@ int envfs_load(char *filename, char *dir) } close(fd); - buf += PAD4(inode_namelen) + PAD4(inode_size) + - sizeof(struct envfs_inode); - size -= PAD4(inode_namelen) + PAD4(inode_size) + + buf += PAD4(inode_size); + size -= headerlen_full + PAD4(inode_size) + sizeof(struct envfs_inode); } diff --git a/include/envfs.h b/include/envfs.h index c6df8c504..3d14fcb9e 100644 --- a/include/envfs.h +++ b/include/envfs.h @@ -5,18 +5,19 @@ #include #endif -#define ENVFS_MAJOR 0 -#define ENVFS_MINOR 1 +#define ENVFS_MAJOR 1 +#define ENVFS_MINOR 0 #define ENVFS_MAGIC 0x798fba79 /* some random number */ #define ENVFS_INODE_MAGIC 0x67a8c78d +#define ENVFS_INODE_END_MAGIC 0x68a8c78d #define ENVFS_END_MAGIC 0x6a87d6cd #define ENVFS_SIGNATURE "barebox envfs" struct envfs_inode { uint32_t magic; /* ENVFS_INODE_MAGIC */ uint32_t size; /* data size in bytes */ - uint32_t namelen; /* The length of the filename _including_ a trailing 0 */ + uint32_t headerlen; /* The length of the filename _including_ a 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 @@ -24,6 +25,11 @@ struct envfs_inode { */ }; +struct envfs_inode_end { + uint32_t magic; /* ENVFS_INODE_END_MAGIC */ + uint32_t mode; /* file mode */ +}; + /* * Superblock information at the beginning of the FS. */ From acef08abb7b7826a7a4a50b65003bb1a3e25fb75 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 22 Aug 2012 12:51:43 +0800 Subject: [PATCH 18/19] envfs: add support of symlink Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- common/environment.c | 101 ++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/common/environment.c b/common/environment.c index fc5c57e88..ce46f4a0e 100644 --- a/common/environment.c +++ b/common/environment.c @@ -54,7 +54,20 @@ int file_size_action(const char *filename, struct stat *statbuf, data->writep += sizeof(struct envfs_inode); data->writep += PAD4(strlen(filename) + 1 - strlen(data->base)); data->writep += sizeof(struct envfs_inode_end); - data->writep += PAD4(statbuf->st_size); + if (S_ISLNK(statbuf->st_mode)) { + char path[PATH_MAX]; + + memset(path, 0, PATH_MAX); + + if (readlink(filename, path, PATH_MAX - 1) < 0) { + perror("read"); + return 0; + } + data->writep += PAD4(strlen(path) + 1); + } else { + data->writep += PAD4(statbuf->st_size); + } + return 1; } @@ -67,13 +80,9 @@ int file_save_action(const char *filename, struct stat *statbuf, int fd; int namelen = strlen(filename) + 1 - strlen(data->base); - debug("handling file %s size %ld namelen %d\n", filename + strlen(data->base), - statbuf->st_size, namelen); - inode = (struct envfs_inode*)data->writep; inode->magic = ENVFS_32(ENVFS_INODE_MAGIC); inode->headerlen = ENVFS_32(PAD4(namelen + sizeof(struct envfs_inode_end))); - inode->size = ENVFS_32(statbuf->st_size); data->writep += sizeof(struct envfs_inode); strcpy(data->writep, filename + strlen(data->base)); @@ -83,19 +92,44 @@ int file_save_action(const char *filename, struct stat *statbuf, inode_end->magic = ENVFS_32(ENVFS_INODE_END_MAGIC); inode_end->mode = ENVFS_32(S_IRWXU | S_IRWXG | S_IRWXO); - fd = open(filename, O_RDONLY); - if (fd < 0) { - printf("Open %s %s\n", filename, errno_str()); - goto out; - } + if (S_ISLNK(statbuf->st_mode)) { + char path[PATH_MAX]; + int len; - if (read(fd, data->writep, statbuf->st_size) < statbuf->st_size) { - perror("read"); - goto out; - } - close(fd); + memset(path, 0, PATH_MAX); - data->writep += PAD4(statbuf->st_size); + if (readlink(filename, path, PATH_MAX - 1) < 0) { + perror("read"); + goto out; + } + len = strlen(path) + 1; + + inode_end->mode |= ENVFS_32(S_IFLNK); + + memcpy(data->writep, path, len); + inode->size = ENVFS_32(len); + data->writep += PAD4(len); + debug("handling symlink %s size %ld namelen %d headerlen %d\n", filename + strlen(data->base), + len, namelen, ENVFS_32(inode->headerlen)); + } else { + debug("handling file %s size %ld namelen %d headerlen %d\n", filename + strlen(data->base), + statbuf->st_size, namelen, ENVFS_32(inode->headerlen)); + + inode->size = ENVFS_32(statbuf->st_size); + fd = open(filename, O_RDONLY); + if (fd < 0) { + printf("Open %s %s\n", filename, errno_str()); + goto out; + } + + if (read(fd, data->writep, statbuf->st_size) < statbuf->st_size) { + perror("read"); + goto out; + } + close(fd); + + data->writep += PAD4(statbuf->st_size); + } out: return 1; @@ -277,22 +311,31 @@ int envfs_load(char *filename, char *dir) goto out; } - fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644); - free(str); - if (fd < 0) { - printf("Open %s\n", errno_str()); - ret = fd; - goto out; - } + if (S_ISLNK(ENVFS_32(inode_end->mode))) { + debug("symlink: %s -> %s\n", str, (char*)buf); + if (symlink((char*)buf, str) < 0) { + printf("symlink: %s -> %s :", str, (char*)buf); + perror(""); + } + free(str); + } else { + fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644); + free(str); + if (fd < 0) { + printf("Open %s\n", errno_str()); + ret = fd; + goto out; + } - ret = write(fd, buf, inode_size); - if (ret < inode_size) { - perror("write"); - ret = -errno; + ret = write(fd, buf, inode_size); + if (ret < inode_size) { + perror("write"); + ret = -errno; + close(fd); + goto out; + } close(fd); - goto out; } - close(fd); buf += PAD4(inode_size); size -= headerlen_full + PAD4(inode_size) + From b65e60792376bb209adfa128e1783cf67af9f13b Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 22 Aug 2012 12:54:19 +0800 Subject: [PATCH 19/19] defautenv: add support of symlink Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- common/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/Makefile b/common/Makefile index d74dffb91..df9f30123 100644 --- a/common/Makefile +++ b/common/Makefile @@ -58,7 +58,7 @@ ifneq ($(CONFIG_DEFAULT_ENVIRONMENT_PATH),"") DEFAULT_ENVIRONMENT_PATH += $(CONFIG_DEFAULT_ENVIRONMENT_PATH) endif -ENV_FILES := $(shell cd $(srctree); for i in $(DEFAULT_ENVIRONMENT_PATH); do find $${i} -type f -exec readlink -f '{}' \;; done) +ENV_FILES := $(shell cd $(srctree); for i in $(DEFAULT_ENVIRONMENT_PATH); do find $${i} -type f ; done) endif # ifdef CONFIG_DEFAULT_ENVIRONMENT