summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:01:37 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:01:37 +0200
commit9db8ed3312a2137b12cb0cb15c4267ead96dbf8b (patch)
treeefa8cebc8db28bf6e7fafae2d920f15d66381047 /fs
parent225b19227203911f9bda410746ef4e366a008852 (diff)
downloadbarebox-9db8ed3312a2137b12cb0cb15c4267ead96dbf8b.tar.gz
barebox-9db8ed3312a2137b12cb0cb15c4267ead96dbf8b.tar.xz
svn_rev_261
WIP Filesystem support
Diffstat (limited to 'fs')
-rw-r--r--fs/cramfs/cramfs.c124
-rw-r--r--fs/fs.c238
-rw-r--r--fs/ramfs.c282
3 files changed, 539 insertions, 105 deletions
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index a5f5a5842e..ee6341b9d2 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -209,11 +209,11 @@ int cramfs_load (char *loadoffset, struct device_d *dev, const char *filename)
(unsigned long) loadoffset);
}
-static int cramfs_list_inode (struct device_d *dev, unsigned long offset)
+static int cramfs_fill_dirent (struct device_d *dev, unsigned long offset, struct dirent *d)
{
struct cramfs_inode *inode = (struct cramfs_inode *)
(dev->map_base + offset);
- char *name, str[20];
+ char *name;
int namelen, nextoff;
/*
@@ -233,80 +233,89 @@ static int cramfs_list_inode (struct device_d *dev, unsigned long offset)
namelen--;
}
- printf (" %s %8d %*.*s", mkmodestr (CRAMFS_16 (inode->mode), str),
- CRAMFS_24 (inode->size), namelen, namelen, name);
-
- if ((CRAMFS_16 (inode->mode) & S_IFMT) == S_IFLNK) {
- /* symbolic link.
- * Unpack the link target, trusting in the inode's size field.
- */
- unsigned long size = CRAMFS_24 (inode->size);
- char *link = malloc (size);
-
- if (link != NULL && cramfs_uncompress (dev->map_base, offset,
- (unsigned long) link)
- == size)
- printf (" -> %*.*s\n", (int) size, (int) size, link);
- else
- printf (" [Error reading link]\n");
- if (link)
- free (link);
- } else
- printf ("\n");
+ d->mode = CRAMFS_16 (inode->mode);
+ d->size = CRAMFS_24 (inode->size);
+ memset(d->name, 0, 256);
+ strncpy(d->name, name, namelen);
return nextoff;
}
-int cramfs_ls (struct device_d *dev, const char *filename)
-{
+struct cramfs_dir {
struct cramfs_inode *inode;
- unsigned long inodeoffset = 0, nextoffset;
unsigned long offset, size;
- char *f;
+ unsigned long inodeoffset;
+ struct dir dir;
+};
- printf("cramfs_ls: %s\n", filename);
+struct dir* cramfs_opendir(struct device_d *_dev, const char *filename)
+{
+ char *f;
+ struct fs_device_d *fsdev = _dev->type_data;
+ struct device_d *dev = fsdev->parent;
- if (cramfs_read_super (dev))
- return -1;
+ struct cramfs_dir *dir = malloc(sizeof(struct cramfs_dir));
+ memset(dir, 0, sizeof(struct cramfs_dir));
+ dir->dir.priv = dir;
if (strlen (filename) == 0 || !strcmp (filename, "/")) {
/* Root directory. Use root inode in super block */
- offset = CRAMFS_GET_OFFSET (&(super.root)) << 2;
- size = CRAMFS_24 (super.root.size);
+ dir->offset = CRAMFS_GET_OFFSET (&(super.root)) << 2;
+ dir->size = CRAMFS_24 (super.root.size);
} else {
f = strdup(filename);
/* Resolve the path */
- offset = cramfs_resolve (dev->map_base,
+ dir->offset = cramfs_resolve (dev->map_base,
CRAMFS_GET_OFFSET (&(super.root)) <<
2, CRAMFS_24 (super.root.size), 1,
strtok (f, "/"));
free(f);
- if (offset <= 0)
- return offset;
+ if (dir->offset <= 0)
+ goto err_free;
/* Resolving was successful. Examine the inode */
- inode = (struct cramfs_inode *) (dev->map_base + offset);
- if (!S_ISDIR (CRAMFS_16 (inode->mode))) {
- /* It's not a directory - list it, and that's that */
- return (cramfs_list_inode (dev, offset) > 0);
+ dir->inode = (struct cramfs_inode *) (dev->map_base + dir->offset);
+ if (!S_ISDIR (CRAMFS_16 (dir->inode->mode))) {
+ /* It's not a directory */
+ goto err_free;
}
/* It's a directory. List files within */
- offset = CRAMFS_GET_OFFSET (inode) << 2;
- size = CRAMFS_24 (inode->size);
+ dir->offset = CRAMFS_GET_OFFSET (dir->inode) << 2;
+ dir->size = CRAMFS_24 (dir->inode->size);
}
+ return &dir->dir;
+
+err_free:
+ free(dir);
+ return NULL;
+}
+
+struct dirent* cramfs_readdir(struct device_d *_dev, struct dir *_dir)
+{
+ struct fs_device_d *fsdev = _dev->type_data;
+ struct device_d *dev = fsdev->parent;
+ struct cramfs_dir *dir = _dir->priv;
+ unsigned long nextoffset;
+
/* List the given directory */
- while (inodeoffset < size) {
- inode = (struct cramfs_inode *) (dev->map_base + offset +
- inodeoffset);
+ if (dir->inodeoffset < dir->size) {
+ dir->inode = (struct cramfs_inode *) (dev->map_base + dir->offset +
+ dir->inodeoffset);
- nextoffset = cramfs_list_inode (dev, offset + inodeoffset);
- if (nextoffset == 0)
- break;
- inodeoffset += sizeof (struct cramfs_inode) + nextoffset;
+ nextoffset = cramfs_fill_dirent (dev, dir->offset + dir->inodeoffset, &_dir->d);
+
+ dir->inodeoffset += sizeof (struct cramfs_inode) + nextoffset;
+ return &_dir->d;
}
+ return NULL;
+}
+int cramfs_closedir(struct device_d *dev, struct dir *_dir)
+{
+ struct cramfs_dir *dir = _dir->priv;
+ free(dir);
return 0;
}
@@ -338,7 +347,14 @@ int cramfs_info (struct device_d *dev)
int cramfs_probe(struct device_d *dev)
{
- if (cramfs_read_super (dev)) {
+ struct fs_device_d *fsdev;
+
+ printf("%s: dev: %p\n",__FUNCTION__, dev);
+
+ fsdev = dev->type_data;
+ printf("%s: fsdev: %p\n",__FUNCTION__, fsdev);
+
+ if (cramfs_read_super (fsdev->parent)) {
printf("no valid cramfs found on %s\n",dev->id);
return -EINVAL;
}
@@ -347,19 +363,21 @@ int cramfs_probe(struct device_d *dev)
}
static struct fs_driver_d cramfs_driver = {
- .type = FS_TYPE_CRAMFS,
- .probe = cramfs_probe,
- .ls = cramfs_ls,
+ .type = FS_TYPE_CRAMFS,
+ .opendir = cramfs_opendir,
+ .readdir = cramfs_readdir,
+ .closedir = cramfs_closedir,
.drv = {
.type = DEVICE_TYPE_FS,
+ .probe = cramfs_probe,
.name = "cramfs",
- .driver_data = &cramfs_driver,
+ .type_data = &cramfs_driver,
}
};
int cramfs_init(void)
{
- return register_fs_driver(&cramfs_driver);
+ return register_driver(&cramfs_driver.drv);
}
device_initcall(cramfs_init);
diff --git a/fs/fs.c b/fs/fs.c
index 824645bca3..ec2373c97b 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -37,26 +37,48 @@ char *mkmodestr(unsigned long mode, char *str)
return str;
}
-static int fs_probe(struct device_d *dev)
-{
- struct fs_device_d *fs_dev = dev->platform_data;
+struct mtab_entry {
+ char path[PATH_MAX];
+ struct mtab_entry *next;
+ struct device_d *dev;
+};
- return fs_dev->driver->probe(fs_dev->parent);
-}
+static struct mtab_entry *mtab;
-int register_fs_driver(struct fs_driver_d *new_fs_drv)
+struct mtab_entry *get_mtab_entry_by_path(const char *_path)
{
- new_fs_drv->drv.probe = fs_probe;
- new_fs_drv->drv.driver_data = new_fs_drv;
+ struct mtab_entry *match = NULL, *e = mtab;
+ char *path, *tok;
+
+ if (*_path != '/')
+ return NULL;
+
+ path = strdup(_path);
+
+ tok = strchr(path + 1, '/');
+ if (tok)
+ *tok = 0;
+
+ while (e) {
+ if (!strcmp(path, e->path)) {
+ match = e;
+ break;
+ }
+ e = e->next;
+ }
+
+ free(path);
- return register_driver(&new_fs_drv->drv);
+ return match ? match : mtab;
}
-int register_filesystem(struct device_d *dev, char *fsname)
+int mount (struct device_d *dev, char *fsname, char *path)
{
- struct fs_device_d *new_fs_dev;
struct driver_d *drv;
struct fs_driver_d *fs_drv;
+ struct mtab_entry *entry;
+ struct fs_device_d *fsdev;
+ int ret;
drv = get_driver_by_name(fsname);
if (!drv) {
@@ -69,72 +91,184 @@ int register_filesystem(struct device_d *dev, char *fsname)
return -EINVAL;
}
- new_fs_dev = malloc(sizeof(struct fs_device_d));
+ /* check if path exists */
+ /* TODO */
- fs_drv = drv->driver_data;
+ fs_drv = drv->type_data;
+ printf("mount: fs_drv: %p\n", fs_drv);
- new_fs_dev->driver = fs_drv;
- new_fs_dev->parent = dev;
- new_fs_dev->dev.platform_data = new_fs_dev;
- new_fs_dev->dev.type = DEVICE_TYPE_FS;
- sprintf(new_fs_dev->dev.name, "%s", fsname);
- sprintf(new_fs_dev->dev.id, "%s", "fs0");
+ if (fs_drv->flags & FS_DRIVER_NO_DEV) {
+ dev = malloc(sizeof(struct device_d));
+ memset(dev, 0, sizeof(struct device_d));
+ sprintf(dev->name, "%s", fsname);
+ dev->type = DEVICE_TYPE_FS;
+ if ((ret = register_device(dev))) {
+ free(dev);
+ return ret;
+ }
+ if (!dev->driver) {
+ /* driver didn't accept the device. Bail out */
+ free(dev);
+ return -EINVAL;
+ }
+ } else {
+ fsdev = malloc(sizeof(struct fs_device_d));
+ memset(fsdev, 0, sizeof(struct fs_device_d));
+ fsdev->parent = dev;
+ sprintf(fsdev->dev.name, "%s", fsname);
+ fsdev->dev.type = DEVICE_TYPE_FS;
+ fsdev->dev.type_data = fsdev;
+ if ((ret = register_device(&fsdev->dev))) {
+ free(fsdev);
+ return ret;
+ }
+ if (!fsdev->dev.driver) {
+ /* driver didn't accept the device. Bail out */
+ free(fsdev);
+ return -EINVAL;
+ }
+ dev = &fsdev->dev;
+ }
- register_device(&new_fs_dev->dev);
+ /* add mtab entry */
+ entry = malloc(sizeof(struct mtab_entry));
+ sprintf(entry->path, "%s", path);
+ entry->dev = dev;
+ entry->next = NULL;
- if (!new_fs_dev->dev.driver) {
- unregister_device(&new_fs_dev->dev);
- return -ENODEV;
+ if (!mtab)
+ mtab = entry;
+ else {
+ struct mtab_entry *e = mtab;
+ while (e->next)
+ e = e->next;
+ e->next = entry;
}
+ printf("mount: mtab->dev: %p\n", mtab->dev);
+
return 0;
}
-int ls(struct device_d *dev, const char *filename)
+int do_mount (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- struct fs_device_d *fs_dev;
+ struct device_d *dev;
+ int ret = 0;
- if (!dev || dev->type != DEVICE_TYPE_FS || !dev->driver)
- return -ENODEV;
+ if (argc != 4) {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
- fs_dev = dev->platform_data;
+ dev = get_device_by_id(argv[1]);
- return fs_dev->driver->ls(fs_dev->parent, filename);
+ if ((ret = mount(dev, argv[2], argv[3]))) {
+ perror("mount", ret);
+ return 1;
+ }
+ return 0;
}
-/* addfs <device> <fstype> */
-int do_addfs ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+struct dir *opendir(const char *pathname)
{
struct device_d *dev;
- int ret = 0;
+ struct fs_driver_d *fsdrv;
+ struct dir *dir;
+ struct mtab_entry *e;
- if (argc != 3) {
- printf ("Usage:\n%s\n", cmdtp->usage);
- return 1;
+ e = get_mtab_entry_by_path(pathname);
+ if (e != mtab)
+ pathname += 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, pathname);
+ if (dir) {
+ dir->dev = dev;
+ dir->fsdrv = fsdrv;
}
- dev = get_device_by_id(argv[1]);
- if (!dev) {
- printf("no such device: %s\n", argv[1]);
- return -ENODEV;
+ return dir;
+}
+
+struct dirent *readdir(struct dir *dir)
+{
+ return dir->fsdrv->readdir(dir->dev, dir);
+}
+
+int closedir(struct dir *dir)
+{
+ return dir->fsdrv->closedir(dir->dev, dir);
+}
+
+static int ls(const char *path)
+{
+ struct dir *dir;
+ struct dirent *d;
+ char modestr[11];
+
+ dir = opendir(path);
+ if (!dir)
+ return -ENOENT;
+
+ while ((d = readdir(dir))) {
+ unsigned long namelen = strlen(d->name);
+ mkmodestr(d->mode, modestr);
+ printf("%s %8d %*.*s\n",modestr, d->size, namelen, namelen, d->name);
}
- if ((ret = register_filesystem(dev, argv[2]))) {
- perror("register_device", ret);
+ closedir(dir);
+
+ return 0;
+}
+
+int do_ls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int ret;
+
+ ret = ls(argv[1]);
+ if (ret) {
+ perror("ls", ret);
return 1;
}
+
return 0;
}
-int do_ls ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+U_BOOT_CMD(
+ ls, 2, 0, do_ls,
+ "ls - list a file or directory\n",
+ "<path> list files on path"
+);
+
+int mkdir (const char *pathname)
{
+ struct fs_driver_d *fsdrv;
struct device_d *dev;
- char *endp;
- int ret;
+ struct mtab_entry *e;
+
+ e = get_mtab_entry_by_path(pathname);
+ if (e != mtab)
+ pathname += strlen(e->path);
+
+ dev = e->dev;
- dev = device_from_spec_str(argv[1], &endp);
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
- ret = ls(dev, endp);
+ if (fsdrv->mkdir)
+ return fsdrv->mkdir(dev, pathname);
+ return -EROFS;
+}
+
+int do_mkdir (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int ret;
+
+ ret = mkdir(argv[1]);
if (ret) {
perror("ls", ret);
return 1;
@@ -144,15 +278,15 @@ int do_ls ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
}
U_BOOT_CMD(
- ls, 2, 0, do_ls,
- "ls - list a file or directory\n",
- "<dev:path> list files on device"
+ mkdir, 2, 0, do_mkdir,
+ "mkdir - create a new directory\n",
+ ""
);
U_BOOT_CMD(
- addfs, 3, 0, do_addfs,
- "addfs - add a filesystem to a device\n",
- " <device> <type> add a filesystem of type 'type' on the given device"
+ mount, 4, 0, do_mount,
+ "mount - mount a filesystem to a device\n",
+ " <device> <type> <path> add a filesystem of type 'type' on the given device"
);
#if 0
U_BOOT_CMD(
diff --git a/fs/ramfs.c b/fs/ramfs.c
new file mode 100644
index 0000000000..7d3d2b6735
--- /dev/null
+++ b/fs/ramfs.c
@@ -0,0 +1,282 @@
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <malloc.h>
+#include <fs.h>
+#include <command.h>
+#include <errno.h>
+#include <asm-generic/errno.h>
+#include <linux/stat.h>
+
+struct handle_d {
+ int (*read)(struct handle_d *, ...);
+ int (*write)(struct handle_d *, ...);
+
+ struct device_d *dev;
+};
+
+struct data_d {
+ char *data;
+ ulong size;
+ struct data_d *next;
+};
+
+struct node_d {
+ char *name;
+ struct node_d *next;
+ struct node_d *child;
+ ulong mode;
+
+ struct handle_d *handle;
+
+ struct data_d *data;
+};
+
+struct filesystem_d {
+ int (*create)(struct device_d *dev, const char *pathname, mode_t mode);
+ struct handle_d *(*open)(struct device_d *dev, const char *pathname, mode_t mode);
+ int (*remove)(struct device_d *dev, const char *pathname);
+ int (*mknod)(struct device_d *dev, const char *pathname, struct handle_d *handle);
+ int (*ls)(struct device_d *dev, const char *pathname);
+};
+
+int create(const char *pathname, ulong mode);
+struct handle_d *open(const char *pathname, ulong type);
+int remove(const char *pathname);
+int mknod(const char *pathname, struct handle_d *handle);
+
+struct ramfs_priv {
+ struct node_d root;
+};
+
+/* ---------------------------------------------------------------*/
+struct node_d * __lookup(struct node_d *node, const char *name)
+{
+// printf("__lookup: %s in %p\n",name, node);
+ node = node->child;
+ if (!node || node->mode != S_IFDIR)
+ return NULL;
+
+ while (node) {
+ if (!strcmp(node->name, name))
+ return node;
+ node = node->next;
+ }
+ return NULL;
+}
+
+struct node_d* rlookup(struct node_d *node, const char *path)
+{
+ static char *buf;
+ char *part;
+//printf("rlookup %s in %p\n",path, node);
+ buf = strdup(path);
+
+ part = strtok(buf, "/");
+ if (!part)
+ goto out;
+
+ do {
+ node = __lookup(node, part);
+ if (!node)
+ goto out;
+ part = strtok(NULL, "/");
+ } while(part);
+
+out:
+ free(buf);
+ return node;
+}
+
+/*
+ * - Remove all multiple slashes
+ * - Remove trailing slashes (except path consists of only
+ * a single slash)
+ * - TODO: illegal characters?
+ */
+void normalise_path(char *path)
+{
+ char *out = path, *in = path;
+
+ while(*in) {
+ if(*in == '/') {
+ *out++ = *in++;
+ while(*in == '/')
+ in++;
+ } else {
+ *out++ = *in++;
+ }
+ }
+
+ /*
+ * Remove trailing slash, but only if
+ * we were given more than a single slash
+ */
+ if (out > path + 1 && *(out - 1) == '/')
+ *(out - 1) = 0;
+
+ *out = 0;
+}
+
+int node_add_child(struct node_d *node, const char *filename, ulong mode)
+{
+ struct node_d *new_node = malloc(sizeof(struct node_d));
+ memset(new_node, 0, sizeof(struct node_d));
+ new_node->name = strdup(filename);
+ new_node->mode = mode;
+
+// printf("node_add_child: %p -> %p\n", node, new_node);
+ if (!node->child) {
+ node->child = new_node;
+ return 0;
+ }
+
+ node = node->child;
+
+ while (node->next)
+ node = node->next;
+
+ node->next = new_node;
+ return 0;
+}
+
+/* ---------------------------------------------------------------*/
+
+int ramfs_create(struct device_d *dev, const char *pathname, ulong mode)
+{
+ struct ramfs_priv *priv = dev->priv;
+ char *path = strdup(pathname);
+ char *file;
+ struct node_d *node;
+
+ normalise_path(path);
+ if (*path == '/')
+ path++;
+
+// printf("after normalise: %s\n",path);
+
+ if ((file = strrchr(path, '/'))) {
+ *file = 0;
+ file++;
+ node = rlookup(&priv->root, path);
+ if (!node)
+ return -ENOENT;
+ } else {
+ file = path;
+ node = &priv->root;
+ }
+
+ if(__lookup(node, file))
+ return -EEXIST;
+
+ return node_add_child(node, file, mode);
+}
+
+int ramfs_mkdir(struct device_d *dev, const char *pathname)
+{
+ return ramfs_create(dev, pathname, S_IFDIR);
+}
+
+int ramfs_probe(struct device_d *dev)
+{
+ struct ramfs_priv *priv = malloc(sizeof(struct ramfs_priv));
+
+ printf("ramfs_probe\n");
+ memset(priv, 0, sizeof(struct ramfs_priv));
+
+ dev->priv = priv;
+
+ priv->root.name = "/";
+ priv->root.mode = S_IFDIR;
+
+ return 0;
+}
+
+static struct handle_d *ramfs_open(struct device_d *dev, const char *pathname)
+{
+ return NULL;
+}
+
+struct dir* ramfs_opendir(struct device_d *dev, const char *pathname)
+{
+ struct dir *dir;
+ struct ramfs_priv *priv = dev->priv;
+ struct node_d *node = rlookup(&priv->root, pathname);
+
+ if (!node)
+ return NULL;
+
+ if (node->mode != S_IFDIR)
+ return NULL;
+
+ dir = malloc(sizeof(struct dir));
+ if (!dir)
+ return NULL;
+
+ dir->node = node->child;
+
+ return dir;
+}
+
+struct dirent* ramfs_readdir(struct device_d *dev, struct dir *dir)
+{
+ if (dir->node) {
+ strcpy(dir->d.name, dir->node->name);
+ dir->d.mode = dir->node->mode;
+ dir->node = dir->node->next;
+ return &dir->d;
+ }
+ return NULL;
+}
+
+int ramfs_closedir(struct device_d *dev, struct dir *dir)
+{
+ free(dir);
+ return 0;
+}
+
+static struct fs_driver_d ramfs_driver = {
+ .type = FS_TYPE_RAMFS,
+ .create = ramfs_create,
+ .open = ramfs_open,
+
+ .mkdir = ramfs_mkdir,
+
+ .opendir = ramfs_opendir,
+ .readdir = ramfs_readdir,
+ .closedir = ramfs_closedir,
+
+ .flags = FS_DRIVER_NO_DEV,
+ .drv = {
+ .type = DEVICE_TYPE_FS,
+ .probe = ramfs_probe,
+ .name = "ramfs",
+ .type_data = &ramfs_driver,
+ }
+};
+
+int ramfs_init(void)
+{
+ return register_driver(&ramfs_driver.drv);
+}
+
+device_initcall(ramfs_init);
+
+/* --------- Testing --------- */
+
+static int do_create ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+// int ret;
+
+ printf("create %s\n",argv[1]);
+// ret = ramfs_create(&ramfs_device, argv[1], S_IFDIR);
+// perror("create", ret);
+ return 0;
+}
+
+U_BOOT_CMD(
+ create, 2, 0, do_create,
+ "ls - list a file or directory\n",
+ "<dev:path> list files on device"
+);
+