9
0
Fork 0

svn_rev_261

WIP Filesystem support
This commit is contained in:
Sascha Hauer 2007-07-05 18:01:37 +02:00 committed by Sascha Hauer
parent 225b192272
commit 9db8ed3312
6 changed files with 582 additions and 119 deletions

View File

@ -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;
unsigned long inodeoffset;
struct dir dir;
};
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;
printf("cramfs_ls: %s\n", filename);
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);

250
fs/fs.c
View File

@ -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;
struct mtab_entry *get_mtab_entry_by_path(const char *_path)
{
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 match ? match : mtab;
}
int register_fs_driver(struct fs_driver_d *new_fs_drv)
int mount (struct device_d *dev, char *fsname, char *path)
{
new_fs_drv->drv.probe = fs_probe;
new_fs_drv->drv.driver_data = new_fs_drv;
return register_driver(&new_fs_drv->drv);
}
int register_filesystem(struct device_d *dev, char *fsname)
{
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,146 @@ 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");
register_device(&new_fs_dev->dev);
if (!new_fs_dev->dev.driver) {
unregister_device(&new_fs_dev->dev);
return -ENODEV;
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;
}
/* add mtab entry */
entry = malloc(sizeof(struct mtab_entry));
sprintf(entry->path, "%s", path);
entry->dev = dev;
entry->next = NULL;
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)
{
struct fs_device_d *fs_dev;
if (!dev || dev->type != DEVICE_TYPE_FS || !dev->driver)
return -ENODEV;
fs_dev = dev->platform_data;
return fs_dev->driver->ls(fs_dev->parent, filename);
}
/* addfs <device> <fstype> */
int do_addfs ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
int do_mount (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
struct device_d *dev;
int ret = 0;
if (argc != 3) {
if (argc != 4) {
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
dev = get_device_by_id(argv[1]);
if (!dev) {
printf("no such device: %s\n", argv[1]);
return -ENODEV;
}
if ((ret = register_filesystem(dev, argv[2]))) {
perror("register_device", ret);
if ((ret = mount(dev, argv[2], argv[3]))) {
perror("mount", ret);
return 1;
}
return 0;
}
int do_ls ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
struct dir *opendir(const char *pathname)
{
struct device_d *dev;
char *endp;
struct fs_driver_d *fsdrv;
struct dir *dir;
struct mtab_entry *e;
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;
}
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);
}
closedir(dir);
return 0;
}
int do_ls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int ret;
dev = device_from_spec_str(argv[1], &endp);
ret = ls(dev, endp);
ret = ls(argv[1]);
if (ret) {
perror("ls", ret);
return 1;
@ -146,13 +242,51 @@ 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"
"<path> list files on path"
);
int mkdir (const char *pathname)
{
struct fs_driver_d *fsdrv;
struct device_d *dev;
struct mtab_entry *e;
e = get_mtab_entry_by_path(pathname);
if (e != mtab)
pathname += strlen(e->path);
dev = e->dev;
fsdrv = (struct fs_driver_d *)dev->driver->type_data;
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;
}
return 0;
}
U_BOOT_CMD(
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(

282
fs/ramfs.c Normal file
View File

@ -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"
);

View File

@ -26,8 +26,11 @@ struct device_d {
*/
unsigned long map_base;
void *platform_data;
void *priv;
void *platform_data; /* board specific information about this device */
void *priv; /* data private to the driver */
void *type_data; /* In case this device is a specific device, this pointer
* points to the type specific device, i.e. eth_device
*/
/* The driver for this device */
struct driver_d *driver;
@ -55,9 +58,10 @@ struct driver_d {
int (*get) (struct device_d*, struct param_d *);
int (*set) (struct device_d*, struct param_d *, value_t val);
void *driver_data;
unsigned long type;
void *type_data;
void *type_data; /* In case this driver is of a specific type, i.e. a filesystem
* driver, this pointer points to the corresponding data struct
*/
};
#define RW_SIZE(x) (x)

View File

@ -6,23 +6,46 @@
#define FS_TYPE_CRAMFS 1
#define FS_TYPE_RAMFS 2
#define PATH_MAX 1024 /* include/linux/limits.h */
struct partition;
struct node_d;
struct dirent {
unsigned long mode;
unsigned long size;
char name[256];
};
struct dir {
struct device_d *dev;
struct fs_driver_d *fsdrv;
struct node_d *node;
struct dirent d;
void *priv; /* private data for the fs driver */
};
#define FS_DRIVER_NO_DEV 1
struct fs_driver_d {
ulong type;
char *name;
int (*ls) (struct device_d *dev, const char *filename);
int (*load) (char *dst, struct device_d *dev, const char *filename);
int (*probe) (struct device_d *dev);
int (*create)(struct device_d *dev, const char *pathname, ulong type);
int (*mkdir)(struct device_d *dev, const char *pathname);
struct handle_d *(*open)(struct device_d *dev, const char *pathname);
struct dir* (*opendir)(struct device_d *dev, const char *pathname);
struct dirent* (*readdir)(struct device_d *dev, struct dir *dir);
int (*closedir)(struct device_d *dev, struct dir *dir);
struct driver_d drv;
unsigned long flags;
};
struct fs_device_d {
ulong type;
char *name;
struct device_d *parent; /* the device we are associated with */
struct device_d dev; /* our own device */
@ -34,4 +57,6 @@ int register_filesystem(struct device_d *dev, char *fsname);
int register_fs_driver(struct fs_driver_d *new_fs_drv);
char *mkmodestr(unsigned long mode, char *str);
#endif /* __FS_H */

View File

@ -68,7 +68,7 @@ int register_device(struct device_d *new_device)
dev = first_device;
if(get_device_by_id(new_device->id)) {
if(*new_device->id && get_device_by_id(new_device->id)) {
printf("device %s already exists\n", new_device->id);
return -EINVAL;
}