diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:01:44 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:01:44 +0200 |
commit | 9df483a88f1679c47944198366dc0269a40e4cfc (patch) | |
tree | e59f9b14a8bf3f3d5c25fb3dbc9a9a204d6b05d0 /fs | |
parent | 96b3a924540baa38372ac4c5747ebf30124d4b00 (diff) | |
download | barebox-9df483a88f1679c47944198366dc0269a40e4cfc.tar.gz barebox-9df483a88f1679c47944198366dc0269a40e4cfc.tar.xz |
svn_rev_338
add rmdir and unlink, make creat more like posix, add common function for prerequites checking
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fs.c | 243 |
1 files changed, 173 insertions, 70 deletions
@@ -6,6 +6,7 @@ #include <malloc.h> #include <linux/stat.h> #include <fcntl.h> +#include <xfuncs.h> char *mkmodestr(unsigned long mode, char *str) { @@ -96,6 +97,13 @@ struct mtab_entry *get_mtab_entry_by_path(const char *_path) return match ? match : mtab; } +struct mtab_entry *mtab_next_entry(struct mtab_entry *e) +{ + if (!e) + return mtab; + return e->next; +} + FILE files[MAX_FILES]; FILE *get_file(void) @@ -118,39 +126,105 @@ void put_file(FILE *f) files[f->no].in_use = 0; } -static FILE* get_file_by_pathname(const char *pathname) +static struct device_d *get_device_by_path(char **path) { - FILE *f; + struct device_d *dev; + struct mtab_entry *e; - f = get_file(); - if (!f) { - errno = -EMFILE; + normalise_path(*path); + + e = get_mtab_entry_by_path(*path); + if (!e) return NULL; + if (e != mtab) + *path += strlen(e->path); + + dev = e->dev; + + return dev; +} + +int dir_is_empty(const char *pathname) +{ + struct dir *dir; + struct dirent *d; + int ret = 1; + + dir = opendir(pathname); + if (!dir) { + errno = -ENOENT; + return -ENOENT; + } + + while ((d = readdir(dir))) { + if (!strcmp(d->name, ".") || !strcmp(d->name, "..")) + continue; + ret = 0; + break; } - return f; + closedir(dir); + return ret; } -int creat(const char *pathname, mode_t mode) +// S_IFREG +// S_IFDIR +#define S_UB_IS_EMPTY (1<<31) +#define S_UB_EXISTS (1<<30) +#define S_UB_DOES_NOT_EXIST (1<<29) +// +static int path_check_prereq(const char *path, unsigned int flags) { - struct mtab_entry *e; - struct device_d *dev; - struct fs_driver_d *fsdrv; + struct stat s; + unsigned int m; - e = get_mtab_entry_by_path(pathname); - if (!e) { + if (stat(path, &s)) { + if (flags & S_UB_DOES_NOT_EXIST) + return 0; errno = -ENOENT; return errno; } - if (e != mtab) - pathname += strlen(e->path); + if (flags == S_UB_EXISTS) + return 0; - dev = e->dev; - fsdrv = (struct fs_driver_d *)dev->driver->type_data; + m = s.st_mode; + + if (S_ISDIR(m)) { + if (flags & S_IFREG) { + errno = -EISDIR; + return errno; + } + if ((flags & S_UB_IS_EMPTY) && !dir_is_empty(path)) { + errno = -ENOTEMPTY; + return errno; + } + } + if ((flags & S_IFDIR) && S_ISREG(m)) { + errno = -ENOTDIR; + return errno; + } + return 0; +} + +int unlink(const char *pathname) +{ + struct device_d *dev; + struct fs_driver_d *fsdrv; + char *p = strdup(pathname); + char *freep = p; - errno = fsdrv->create(dev, pathname, S_IFREG); + if (path_check_prereq(pathname, S_IFREG)) + return errno; + dev = get_device_by_path(&p); + if (!dev) + goto out; + fsdrv = (struct fs_driver_d *)dev->driver->type_data; + + errno = fsdrv->unlink(dev, p); +out: + free(freep); return errno; } @@ -158,32 +232,36 @@ int open(const char *pathname, int flags) { struct device_d *dev; struct fs_driver_d *fsdrv; - struct mtab_entry *e; FILE *f; int exist; struct stat s; + char *path; - exist = stat(pathname, &s) == 0 ? 1 : 0; + exist = (stat(pathname, &s) == 0) ? 1 : 0; - if (!exist && !(flags & O_CREAT)) - return -EEXIST; - - f = get_file_by_pathname(pathname); + if (exist && (s.st_mode & S_IFDIR)) { + errno = -EISDIR; + return errno; + } - e = get_mtab_entry_by_path(pathname); - if (!e) { - /* This can only happen when nothing is mounted */ + if (!exist && !(flags & O_CREAT)) { errno = -ENOENT; - goto out; + return errno; } - /* Adjust the pathname to the root of the device */ - if (e != mtab) - pathname += strlen(e->path); + f = get_file(); + if (!f) { + errno = -EMFILE; + return errno; + } - dev = e->dev; + path = strdup(pathname); + dev = get_device_by_path(&path); + if (!dev) + goto out; fsdrv = (struct fs_driver_d *)dev->driver->type_data; + f->dev = dev; f->flags = flags; @@ -201,22 +279,28 @@ int open(const char *pathname, int flags) if (errno) goto out; - if (flags & O_APPEND) - f->pos = f->size; - if (flags & O_TRUNC) { errno = fsdrv->truncate(dev, f, 0); if (errno) goto out; } + if (flags & O_APPEND) + f->pos = f->size; + return f->no; out: put_file(f); + free(path); return errno; } +int creat(const char *pathname, mode_t mode) +{ + return open(pathname, O_CREAT | O_WRONLY | O_TRUNC); +} + int read(int fd, void *buf, size_t count) { struct device_d *dev; @@ -244,7 +328,7 @@ ssize_t write(int fd, const void *buf, size_t count) FILE *f = &files[fd]; dev = f->dev; - printf("WRITE: dev: %p\n",dev); +// printf("WRITE: dev: %p\n",dev); fsdrv = (struct fs_driver_d *)dev->driver->type_data; if (f->pos + count > f->size) { errno = fsdrv->truncate(dev, f, f->pos + count); @@ -305,13 +389,13 @@ int close(int fd) return errno; } -int mount(struct device_d *dev, char *fsname, char *path) +int mount(struct device_d *parent_device, char *fsname, char *path) { struct driver_d *drv; struct fs_driver_d *fs_drv; struct mtab_entry *entry; struct fs_device_d *fsdev; - struct dir *dir; + struct device_d *dev; int ret; errno = 0; @@ -328,12 +412,8 @@ int mount(struct device_d *dev, char *fsname, char *path) } if (mtab) { - /* check if path exists and is a directory */ - if (!(dir = opendir(path))) { - errno = -ENOTDIR; + if (path_check_prereq(path, S_IFDIR)) goto out; - } - closedir(dir); } else { /* no mtab, so we only allow to mount on '/' */ if (*path != '/' || *(path + 1)) { @@ -345,8 +425,7 @@ int mount(struct device_d *dev, char *fsname, char *path) fs_drv = drv->type_data; if (fs_drv->flags & FS_DRIVER_NO_DEV) { - dev = malloc(sizeof(struct device_d)); - memset(dev, 0, sizeof(struct device_d)); + dev = xzalloc(sizeof(struct device_d)); sprintf(dev->name, "%s", fsname); dev->type = DEVICE_TYPE_FS; if ((ret = register_device(dev))) { @@ -361,9 +440,13 @@ int mount(struct device_d *dev, char *fsname, char *path) goto out; } } else { - fsdev = malloc(sizeof(struct fs_device_d)); - memset(fsdev, 0, sizeof(struct fs_device_d)); - fsdev->parent = dev; + if (!parent_device) { + printf("need device for driver %s\n", fsname); + errno = -ENODEV; + goto out; + } + fsdev = xzalloc(sizeof(struct fs_device_d)); + fsdev->parent = parent_device; sprintf(fsdev->dev.name, "%s", fsname); fsdev->dev.type = DEVICE_TYPE_FS; fsdev->dev.type_data = fsdev; @@ -385,6 +468,7 @@ int mount(struct device_d *dev, char *fsname, char *path) entry = malloc(sizeof(struct mtab_entry)); sprintf(entry->path, "%s", path); entry->dev = dev; + entry->parent_device = parent_device; entry->next = NULL; if (!mtab) @@ -432,25 +516,20 @@ int umount(const char *pathname) struct dir *opendir(const char *pathname) { + struct dir *dir = NULL; struct device_d *dev; struct fs_driver_d *fsdrv; - struct dir *dir = NULL; - struct mtab_entry *e; char *p = strdup(pathname); char *freep = p; - normalise_path(p); + if (path_check_prereq(pathname, S_IFDIR)) + return NULL; - e = get_mtab_entry_by_path(p); - if (!e) + dev = get_device_by_path(&p); + if (!dev) goto out; - if (e != mtab) - p += strlen(e->path); - - dev = e->dev; -// printf("opendir: dev: %p\n",dev); - fsdrv = (struct fs_driver_d *)dev->driver->type_data; + // printf("opendir: fsdrv: %p\n",fsdrv); dir = fsdrv->opendir(dev, p); @@ -513,27 +592,51 @@ int mkdir (const char *pathname) { struct fs_driver_d *fsdrv; struct device_d *dev; - struct mtab_entry *e; + char *p = strdup(pathname); + char *freep = p; - e = get_mtab_entry_by_path(pathname); - if (!e) { - errno = -ENOENT; - return -ENOENT; + if (path_check_prereq(pathname, S_UB_DOES_NOT_EXIST)) + return errno; + + dev = get_device_by_path(&p); + if (!dev) + goto out; + fsdrv = (struct fs_driver_d *)dev->driver->type_data; + + if (fsdrv->mkdir) { + errno = fsdrv->mkdir(dev, p); + goto out; } - if (e != mtab) - pathname += strlen(e->path); + errno = -EROFS; +out: + free(freep); + return errno; +} - dev = e->dev; +int rmdir (const char *pathname) +{ + struct fs_driver_d *fsdrv; + struct device_d *dev; + char *p = strdup(pathname); + char *freep = p; + + if (path_check_prereq(pathname, S_IFDIR | S_UB_IS_EMPTY)) + return errno; + dev = get_device_by_path(&p); + if (!dev) + goto out; fsdrv = (struct fs_driver_d *)dev->driver->type_data; - if (fsdrv->mkdir) { - errno = fsdrv->mkdir(dev, pathname); - return errno; + if (fsdrv->rmdir) { + errno = fsdrv->rmdir(dev, p); + goto out; } errno = -EROFS; - return -EROFS; +out: + free(freep); + return errno; } |