summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:01:38 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:01:38 +0200
commitcf7a56fc78a3304fd9ad4b22c6da30cc452a5b4b (patch)
treed74423adf47b86daea48bac089b9ecc32afe4d42
parent5c1f0869414930fdebc35755217ead72d39879ec (diff)
downloadbarebox-cf7a56fc78a3304fd9ad4b22c6da30cc452a5b4b.tar.gz
barebox-cf7a56fc78a3304fd9ad4b22c6da30cc452a5b4b.tar.xz
svn_rev_268
WIP
-rw-r--r--common/Makefile3
-rw-r--r--common/cmd_flash.c2
-rw-r--r--common/cmd_mem.c23
-rw-r--r--common/env.c6
-rw-r--r--common/mtdpart.c4
-rw-r--r--fs/cramfs/cramfs.c240
-rw-r--r--fs/fs.c324
-rw-r--r--fs/ramfs.c89
-rw-r--r--include/common.h2
-rw-r--r--include/driver.h9
-rw-r--r--include/errno.h4
-rw-r--r--include/fs.h43
-rw-r--r--lib_generic/misc.c39
-rw-r--r--net/tftp.c2
14 files changed, 514 insertions, 276 deletions
diff --git a/common/Makefile b/common/Makefile
index bbbf8ad0c9..e0e4cd044c 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -90,3 +90,6 @@ obj-y += mtdpart.o
obj-y += env.o
obj-y += startup.o
obj-y += misc.o
+
+obj-y += cmd_fs.o
+
diff --git a/common/cmd_flash.c b/common/cmd_flash.c
index 4395ca930e..43c44f2818 100644
--- a/common/cmd_flash.c
+++ b/common/cmd_flash.c
@@ -51,7 +51,7 @@ int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
return 1;
}
- erase(mem.device, mem.size, mem.start);
+ dev_erase(mem.device, mem.size, mem.start);
return 0;
}
diff --git a/common/cmd_mem.c b/common/cmd_mem.c
index 1da58d22bb..0a026f6b2a 100644
--- a/common/cmd_mem.c
+++ b/common/cmd_mem.c
@@ -131,9 +131,9 @@ int do_mem_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
do {
now = min(RW_BUF_SIZE, nbytes);
- r = read(mem.device, rw_buf, now, offs, RW_SIZE(size));
+ r = dev_read(mem.device, rw_buf, now, offs, RW_SIZE(size));
if (r <= 0) {
- perror("read", r);
+ perror("read");
return r;
}
@@ -184,7 +184,7 @@ int do_mem_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
count = size;
if (count == size) {
- return write(mem.device, (uchar *)&writeval, count, mem.start, RW_SIZE(size));
+ return dev_write(mem.device, (uchar *)&writeval, count, mem.start, RW_SIZE(size));
} else {
printf("write multiple not yet implemented\n");
}
@@ -300,11 +300,11 @@ int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
while (count > 0) {
now = min(RW_BUF_SIZE, count);
- ret = read(src.device, rw_buf, now, src.start + offset, RW_SIZE(size));
+ ret = dev_read(src.device, rw_buf, now, src.start + offset, RW_SIZE(size));
if (ret <= 0)
return ret;
- ret = write(dst.device, rw_buf, ret, dst.start + offset, RW_SIZE(size));
+ ret = dev_write(dst.device, rw_buf, ret, dst.start + offset, RW_SIZE(size));
if (ret <= 0)
return ret;
if (ret < now)
@@ -432,14 +432,19 @@ static void memcpy_sz(void *_dst, void *_src, ulong count, ulong rwsize)
ssize_t mem_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong rwflags)
{
- memcpy_sz(buf, (void *)(dev->map_base + offset), count, rwflags & RW_SIZE_MASK);
- return count;
+ ulong size;
+ size = min(count, dev->size - offset);
+ printf("mem_read: dev->map_base: %p size: %d offset: %d\n",dev->map_base, size, offset);
+ memcpy_sz(buf, (void *)(dev->map_base + offset), size, rwflags & RW_SIZE_MASK);
+ return size;
}
ssize_t mem_write(struct device_d *dev, void *buf, size_t count, ulong offset, ulong rwflags)
{
- memcpy_sz((void *)(dev->map_base + offset), buf, count, rwflags & RW_SIZE_MASK);
- return count;
+ ulong size;
+ size = min(count, dev->size - offset);
+ memcpy_sz((void *)(dev->map_base + offset), buf, size, rwflags & RW_SIZE_MASK);
+ return size;
}
static struct device_d mem_dev = {
diff --git a/common/env.c b/common/env.c
index d8fb867957..8a69017218 100644
--- a/common/env.c
+++ b/common/env.c
@@ -123,7 +123,7 @@ int add_env_spec(char *spec)
env_list->next = NULL;
- err = read(info.device, env, env_size, info.start, 0);
+ err = dev_read(info.device, env, env_size, info.start, 0);
if (err != env_size)
goto err_out;
@@ -206,13 +206,13 @@ int saveenv(void)
*(ulong *)env = crc32(0, env + sizeof(ulong), env_size - sizeof(ulong));
- ret = erase(info.device, info.size, info.start);
+ ret = dev_erase(info.device, info.size, info.start);
if (ret) {
printf("unable to erase\n");
goto err_out;
}
- ret = write(info.device, env, info.size, info.start, 0);
+ ret = dev_write(info.device, env, info.size, info.start, 0);
if (ret < 0) {
printf("unable to write\n");
goto err_out;
diff --git a/common/mtdpart.c b/common/mtdpart.c
index 788aeda060..3b4cc7f715 100644
--- a/common/mtdpart.c
+++ b/common/mtdpart.c
@@ -196,14 +196,14 @@ ssize_t part_read(struct device_d *dev, void *buf, size_t count, unsigned long o
{
struct partition *part = dev->platform_data;
- return read(part->parent, buf, count, offset + part->offset, flags);
+ return dev_read(part->parent, buf, count, offset + part->offset, flags);
}
ssize_t part_write(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
{
struct partition *part = dev->platform_data;
- return write(part->parent, buf, count, offset + part->offset, flags);
+ return dev_write(part->parent, buf, count, offset + part->offset, flags);
}
struct driver_d part_driver = {
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index 95dfad97ac..25631a6b74 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -28,6 +28,7 @@
#include <malloc.h>
#include <driver.h>
#include <init.h>
+#include <errno.h>
#include <asm-generic/errno.h>
#include <fs.h>
@@ -42,49 +43,56 @@
#define CRAMINO(x) (CRAMFS_GET_OFFSET(x) ? CRAMFS_GET_OFFSET(x)<<2 : 1)
#define OFFSET(x) ((x)->i_ino)
-struct cramfs_super super;
+struct cramfs_priv {
+ struct cramfs_super super;
+ int curr_block;
+ struct cramfs_inode *inode;
+ char buf[4096];
+ int curr_block_len;
+};
-static int cramfs_read_super (struct device_d *dev)
+static int cramfs_read_super (struct device_d *dev, struct cramfs_priv *priv)
{
unsigned long root_offset;
+ struct cramfs_super *super = &priv->super;
- if (read(dev, &super, sizeof (super), 0, 0) < sizeof (super)) {
+ if (dev_read(dev, super, sizeof (struct cramfs_super), 0, 0) < sizeof (struct cramfs_super)) {
printf("read superblock failed\n");
return -EINVAL;
}
/* Do sanity checks on the superblock */
- if (super.magic != CRAMFS_32 (CRAMFS_MAGIC)) {
+ if (super->magic != CRAMFS_32 (CRAMFS_MAGIC)) {
/* check at 512 byte offset */
- if (read(dev, &super, sizeof (super), 512, 0) < sizeof (super)) {
+ if (dev_read(dev, super, sizeof (struct cramfs_super), 512, 0) < sizeof (struct cramfs_super)) {
printf("read superblock failed\n");
return -EINVAL;
}
- if (super.magic != CRAMFS_32 (CRAMFS_MAGIC)) {
+ if (super->magic != CRAMFS_32 (CRAMFS_MAGIC)) {
printf ("cramfs: wrong magic\n");
return -1;
}
}
/* flags is reused several times, so swab it once */
- super.flags = CRAMFS_32 (super.flags);
- super.size = CRAMFS_32 (super.size);
+ super->flags = CRAMFS_32 (super->flags);
+ super->size = CRAMFS_32 (super->size);
/* get feature flags first */
- if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
+ if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) {
printf ("cramfs: unsupported filesystem features\n");
return -1;
}
/* Check that the root inode is in a sane state */
- if (!S_ISDIR (CRAMFS_16 (super.root.mode))) {
+ if (!S_ISDIR (CRAMFS_16 (super->root.mode))) {
printf ("cramfs: root is not a directory\n");
return -1;
}
- root_offset = CRAMFS_GET_OFFSET (&(super.root)) << 2;
+ root_offset = CRAMFS_GET_OFFSET (&(super->root)) << 2;
if (root_offset == 0) {
printf ("cramfs: empty filesystem");
- } else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
+ } else if (!(super->flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
((root_offset != sizeof (struct cramfs_super)) &&
(root_offset != 512 + sizeof (struct cramfs_super)))) {
printf ("cramfs: bad root offset %lu\n", root_offset);
@@ -153,61 +161,10 @@ static unsigned long cramfs_resolve (unsigned long begin, unsigned long offset,
inodeoffset = nextoffset;
}
+ printf ("can't find corresponding entry\n");
return 0;
}
-static int cramfs_uncompress (unsigned long begin, unsigned long offset,
- unsigned long loadoffset)
-{
- struct cramfs_inode *inode = (struct cramfs_inode *) (begin + offset);
- unsigned long *block_ptrs = (unsigned long *)
- (begin + (CRAMFS_GET_OFFSET (inode) << 2));
- unsigned long curr_block = (CRAMFS_GET_OFFSET (inode) +
- (((CRAMFS_24 (inode->size)) +
- 4095) >> 12)) << 2;
- int size, total_size = 0;
- int i;
-
- cramfs_uncompress_init ();
-
- for (i = 0; i < ((CRAMFS_24 (inode->size) + 4095) >> 12); i++) {
- size = cramfs_uncompress_block ((void *) loadoffset,
- (void *) (begin + curr_block),
- (CRAMFS_32 (block_ptrs[i]) -
- curr_block));
- if (size < 0)
- return size;
- loadoffset += size;
- total_size += size;
- curr_block = CRAMFS_32 (block_ptrs[i]);
- }
-
- cramfs_uncompress_exit ();
- return total_size;
-}
-
-int cramfs_load (char *loadoffset, struct device_d *dev, const char *filename)
-{
- unsigned long offset;
- char *f;
- if (cramfs_read_super (dev))
- return -1;
-
- f = strdup(filename);
- offset = cramfs_resolve (dev->map_base,
- CRAMFS_GET_OFFSET (&(super.root)) << 2,
- CRAMFS_24 (super.root.size), 0,
- strtok (f, "/"));
-
- free(f);
-
- if (offset <= 0)
- return offset;
-
- return cramfs_uncompress (dev->map_base, offset,
- (unsigned long) loadoffset);
-}
-
static int cramfs_fill_dirent (struct device_d *dev, unsigned long offset, struct dirent *d)
{
struct cramfs_inode *inode = (struct cramfs_inode *)
@@ -232,8 +189,6 @@ static int cramfs_fill_dirent (struct device_d *dev, unsigned long offset, struc
namelen--;
}
- d->mode = CRAMFS_16 (inode->mode);
- d->size = CRAMFS_24 (inode->size);
memset(d->name, 0, 256);
strncpy(d->name, name, namelen);
@@ -250,6 +205,7 @@ struct cramfs_dir {
struct dir* cramfs_opendir(struct device_d *_dev, const char *filename)
{
char *f;
+ struct cramfs_priv *priv = _dev->priv;
struct fs_device_d *fsdev = _dev->type_data;
struct device_d *dev = fsdev->parent;
@@ -259,14 +215,14 @@ struct dir* cramfs_opendir(struct device_d *_dev, const char *filename)
if (strlen (filename) == 0 || !strcmp (filename, "/")) {
/* Root directory. Use root inode in super block */
- dir->offset = CRAMFS_GET_OFFSET (&(super.root)) << 2;
- dir->size = CRAMFS_24 (super.root.size);
+ dir->offset = CRAMFS_GET_OFFSET (&(priv->super.root)) << 2;
+ dir->size = CRAMFS_24 (priv->super.root.size);
} else {
f = strdup(filename);
/* Resolve the path */
dir->offset = cramfs_resolve (dev->map_base,
- CRAMFS_GET_OFFSET (&(super.root)) <<
- 2, CRAMFS_24 (super.root.size), 1,
+ CRAMFS_GET_OFFSET (&(priv->super.root)) <<
+ 2, CRAMFS_24 (priv->super.root.size), 1,
strtok (f, "/"));
free(f);
if (dir->offset <= 0)
@@ -291,7 +247,7 @@ err_free:
return NULL;
}
-struct dirent* cramfs_readdir(struct device_d *_dev, struct dir *_dir)
+static 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;
@@ -311,14 +267,123 @@ struct dirent* cramfs_readdir(struct device_d *_dev, struct dir *_dir)
return NULL;
}
-int cramfs_closedir(struct device_d *dev, struct dir *_dir)
+static int cramfs_closedir(struct device_d *dev, struct dir *_dir)
{
struct cramfs_dir *dir = _dir->priv;
free(dir);
return 0;
}
-int cramfs_info (struct device_d *dev)
+static int cramfs_open(struct device_d *_dev, FILE *file, const char *filename)
+{
+ struct cramfs_priv *priv = _dev->priv;
+ struct fs_device_d *fsdev = _dev->type_data;
+ struct device_d *dev = fsdev->parent;
+ char *f;
+ unsigned long offset;
+
+ f = strdup(filename);
+ offset = cramfs_resolve (dev->map_base,
+ CRAMFS_GET_OFFSET (&(priv->super.root)) << 2,
+ CRAMFS_24 (priv->super.root.size), 0,
+ strtok (f, "/"));
+
+ free(f);
+
+ if (offset <= 0)
+ return -ENOENT;
+
+ file->pos = 0;
+ file->inode = (struct cramfs_inode *)(dev->map_base + offset);
+
+ return 0;
+}
+
+static int cramfs_close(struct device_d *dev, FILE *f)
+{
+ return 0;
+}
+
+static int cramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
+{
+ struct cramfs_priv *priv = _dev->priv;
+ struct fs_device_d *fsdev = _dev->type_data;
+ struct device_d *dev = fsdev->parent;
+ struct cramfs_inode *inode = (struct cramfs_inode *)f->inode;
+ unsigned int blocknr;
+ int outsize = 0;
+ unsigned long *block_ptrs = (unsigned long *)
+ (dev->map_base + (CRAMFS_GET_OFFSET (inode) << 2));
+ int ofs = f->pos % 4096;
+
+ if (f->pos + size > inode->size)
+ size = inode->size - f->pos;
+
+ while (size) {
+ unsigned long base;
+ int copy;
+
+ blocknr = f->pos >> 12;
+ if (blocknr != priv->curr_block || priv->inode != inode) {
+ if (blocknr)
+ base = CRAMFS_32 (block_ptrs[blocknr - 1]);
+ else
+ base = (CRAMFS_GET_OFFSET(inode) + (((CRAMFS_24 (inode->size)) + 4095) >> 12)) << 2;
+
+ priv->curr_block_len = cramfs_uncompress_block (priv->buf,
+ (void *)(dev->map_base + base), 4096);
+
+// printf("READ blocknr: %d len %d\n",blocknr,priv->curr_block_len );
+ if (priv->curr_block_len <= 0)
+ break;
+
+ priv->curr_block = blocknr;
+ priv->inode = inode;
+ }
+
+ copy = min(priv->curr_block_len, size);
+
+ memcpy(buf, priv->buf + ofs, copy);
+ ofs = 0;
+
+ f->pos += copy;
+ outsize += copy;
+ size -= copy;
+ buf += copy;
+ }
+
+ return outsize;
+}
+
+static int cramfs_stat(struct device_d *_dev, const char *filename, struct stat *stat)
+{
+ struct cramfs_priv *priv = _dev->priv;
+ struct fs_device_d *fsdev = _dev->type_data;
+ struct device_d *dev = fsdev->parent;
+ struct cramfs_inode *inode;
+ char *f;
+ unsigned long offset;
+
+ f = strdup(filename);
+ offset = cramfs_resolve (dev->map_base,
+ CRAMFS_GET_OFFSET (&(priv->super.root)) << 2,
+ CRAMFS_24 (priv->super.root.size), 1,
+ strtok (f, "/"));
+
+ free(f);
+
+ if (offset < 0)
+ return -ENOENT;
+
+ inode = (struct cramfs_inode *) (dev->map_base + offset);
+
+ stat->st_mode = CRAMFS_16 (inode->mode);
+ stat->st_size = CRAMFS_24 (inode->size);
+
+ return 0;
+}
+#if 0
+static int cramfs_info (struct device_d *dev)
{
if (cramfs_read_super (dev))
return 0;
@@ -343,32 +408,53 @@ int cramfs_info (struct device_d *dev)
return 1;
}
+#endif
int cramfs_probe(struct device_d *dev)
{
struct fs_device_d *fsdev;
-
- printf("%s: dev: %p\n",__FUNCTION__, dev);
+ struct cramfs_priv *priv;
fsdev = dev->type_data;
- printf("%s: fsdev: %p\n",__FUNCTION__, fsdev);
- if (cramfs_read_super (fsdev->parent)) {
+ priv = malloc(sizeof(struct cramfs_priv));
+ dev->priv = priv;
+
+ if (cramfs_read_super (fsdev->parent, priv)) {
printf("no valid cramfs found on %s\n",dev->id);
+ free(priv);
return -EINVAL;
}
+ priv->curr_block = -1;
+
+ cramfs_uncompress_init ();
+ return 0;
+}
+
+int cramfs_remove(struct device_d *dev)
+{
+ struct cramfs_priv *priv = dev->priv;
+
+ cramfs_uncompress_exit ();
+ free(priv);
+
return 0;
}
static struct fs_driver_d cramfs_driver = {
.type = FS_TYPE_CRAMFS,
+ .open = cramfs_open,
+ .close = cramfs_close,
+ .read = cramfs_read,
.opendir = cramfs_opendir,
.readdir = cramfs_readdir,
.closedir = cramfs_closedir,
+ .stat = cramfs_stat,
.drv = {
.type = DEVICE_TYPE_FS,
.probe = cramfs_probe,
+ .remove = cramfs_remove,
.name = "cramfs",
.type_data = &cramfs_driver,
}
diff --git a/fs/fs.c b/fs/fs.c
index 0bc9d200f4..4ed3e39f4e 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1,5 +1,4 @@
#include <common.h>
-#include <command.h>
#include <fs.h>
#include <driver.h>
#include <errno.h>
@@ -37,11 +36,35 @@ char *mkmodestr(unsigned long mode, char *str)
return str;
}
-struct mtab_entry {
- char path[PATH_MAX];
- struct mtab_entry *next;
- struct device_d *dev;
-};
+/*
+ * - 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;
+}
static struct mtab_entry *mtab;
@@ -72,30 +95,149 @@ struct mtab_entry *get_mtab_entry_by_path(const char *_path)
return match ? match : mtab;
}
+FILE files[MAX_FILES];
+
+FILE *get_file(void)
+{
+ int i;
+
+ for (i = 3; i < MAX_FILES; i++) {
+ if (!files[i].used) {
+ files[i].used = 1;
+ files[i].no = i;
+ memset(&files[i], 0, sizeof(FILE));
+ return &files[i];
+ }
+ }
+ return NULL;
+}
+
+void put_file(FILE *f)
+{
+ files[f->no].used = 0;
+}
+
+int open(const char *pathname, int flags)
+{
+ struct device_d *dev;
+ struct fs_driver_d *fsdrv;
+ struct mtab_entry *e;
+ FILE *f;
+ int ret;
+
+ f = get_file();
+ if (!f) {
+ errno = -EMFILE;
+ return errno;
+ }
+
+ if (!strncmp(pathname, "/dev/", 5)) {
+ dev = get_device_by_id(pathname + 5);
+ f->dev = dev;
+ } else {
+ e = get_mtab_entry_by_path(pathname);
+ if (!e) {
+ errno = -ENOENT;
+ goto out;
+ }
+
+ if (e != mtab)
+ pathname += strlen(e->path);
+
+ dev = e->dev;
+
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
+ f->dev = dev;
+
+ ret = fsdrv->open(dev, f, pathname);
+ if (ret) {
+ errno = ret;
+ goto out;
+ }
+ }
+
+ return f->no;
+
+out:
+ put_file(f);
+ return errno;
+}
+
+int read(int fd, void *buf, size_t count)
+{
+ struct device_d *dev;
+ struct fs_driver_d *fsdrv;
+ FILE *f = &files[fd];
+
+ dev = f->dev;
+ if (dev->type == DEVICE_TYPE_FS) {
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
+ errno = fsdrv->read(dev, f, buf, count);
+ return errno;
+ } else {
+ errno = dev->driver->read(dev, buf, count, f->pos, 0); /* FIXME: flags */
+ if (errno > 0)
+ f->pos += errno;
+ return errno;
+ }
+}
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+ return -EROFS;
+}
+
+int close(int fd)
+{
+ struct device_d *dev;
+ struct fs_driver_d *fsdrv;
+ FILE *f = &files[fd];
+
+ dev = f->dev;
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
+
+ put_file(f);
+ return fsdrv->close(dev, f);
+}
+
int mount (struct device_d *dev, 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;
int ret;
+ errno = 0;
+
drv = get_driver_by_name(fsname);
if (!drv) {
- printf("no driver for fstype %s\n", fsname);
- return -EINVAL;
+ errno = -ENODEV;
+ goto out;
}
if (drv->type != DEVICE_TYPE_FS) {
- printf("driver %s is no filesystem driver\n");
- return -EINVAL;
+ errno = -EINVAL;
+ goto out;
}
- /* check if path exists */
- /* TODO */
+ if (mtab) {
+ /* check if path exists and is a directory */
+ if (!(dir = opendir(path))) {
+ errno = -ENOTDIR;
+ goto out;
+ }
+ closedir(dir);
+ } else {
+ /* no mtab, so we only allow to mount on '/' */
+ if (*path != '/' || *(path + 1)) {
+ errno = -ENOTDIR;
+ goto out;
+ }
+ }
fs_drv = drv->type_data;
- printf("mount: fs_drv: %p\n", fs_drv);
if (fs_drv->flags & FS_DRIVER_NO_DEV) {
dev = malloc(sizeof(struct device_d));
@@ -104,12 +246,14 @@ int mount (struct device_d *dev, char *fsname, char *path)
dev->type = DEVICE_TYPE_FS;
if ((ret = register_device(dev))) {
free(dev);
- return ret;
+ errno = ret;
+ goto out;
}
if (!dev->driver) {
/* driver didn't accept the device. Bail out */
free(dev);
- return -EINVAL;
+ errno = -EINVAL;
+ goto out;
}
} else {
fsdev = malloc(sizeof(struct fs_device_d));
@@ -120,12 +264,14 @@ int mount (struct device_d *dev, char *fsname, char *path)
fsdev->dev.type_data = fsdev;
if ((ret = register_device(&fsdev->dev))) {
free(fsdev);
- return ret;
+ errno = ret;
+ goto out;
}
if (!fsdev->dev.driver) {
/* driver didn't accept the device. Bail out */
free(fsdev);
- return -EINVAL;
+ errno = -EINVAL;
+ goto out;
}
dev = &fsdev->dev;
}
@@ -144,28 +290,38 @@ int mount (struct device_d *dev, char *fsname, char *path)
e = e->next;
e->next = entry;
}
-
- printf("mount: mtab->dev: %p\n", mtab->dev);
-
- return 0;
+out:
+ return errno;
}
-int do_mount (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+int umount(const char *pathname)
{
- struct device_d *dev;
- int ret = 0;
+ struct mtab_entry *entry = mtab;
+ struct mtab_entry *last = mtab;
+ char *p = strdup(pathname);
+
+ normalise_path(p);
- if (argc != 4) {
- printf ("Usage:\n%s\n", cmdtp->usage);
- return 1;
+ while(entry && strcmp(p, entry->path)) {
+ last = entry;
+ entry = entry->next;
}
- dev = get_device_by_id(argv[1]);
+ free(p);
- if ((ret = mount(dev, argv[2], argv[3]))) {
- perror("mount", ret);
- return 1;
+ if (!entry) {
+ errno = -EFAULT;
+ return errno;
}
+
+ if (entry == mtab)
+ mtab = mtab->next;
+ else
+ last->next = entry->next;
+
+ unregister_device(entry->dev);
+ free(entry);
+
return 0;
}
@@ -207,20 +363,59 @@ int closedir(struct dir *dir)
return dir->fsdrv->closedir(dir->dev, dir);
}
-static int ls(const char *path)
+int stat(const char *filename, struct stat *s)
+{
+ struct device_d *dev;
+ struct fs_driver_d *fsdrv;
+ struct mtab_entry *e;
+ char *f = strdup(filename);
+
+ memset(s, 0, sizeof(struct stat));
+
+ normalise_path(f);
+
+ e = get_mtab_entry_by_path(f);
+ if (!e) {
+ errno = -ENOENT;
+ goto out;
+ }
+ if (e != mtab)
+ f += strlen(e->path);
+
+ dev = e->dev;
+
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
+
+ errno = fsdrv->stat(dev, f, s);
+out:
+ free(f);
+ return errno;
+}
+
+int ls(const char *path)
{
struct dir *dir;
struct dirent *d;
char modestr[11];
+ char tmp[PATH_MAX];
+ struct stat s;
dir = opendir(path);
- if (!dir)
+ if (!dir) {
+ errno = -ENOENT;
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);
+ sprintf(tmp, "%s/%s", path, d->name);
+ if (stat(tmp, &s)) {
+ perror("stat");
+ return errno;
+ }
+
+ mkmodestr(s.st_mode, modestr);
+ printf("%s %8d %*.*s\n",modestr, s.st_size, namelen, namelen, d->name);
}
closedir(dir);
@@ -228,25 +423,6 @@ static int ls(const char *path)
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;
-}
-
-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;
@@ -254,8 +430,11 @@ int mkdir (const char *pathname)
struct mtab_entry *e;
e = get_mtab_entry_by_path(pathname);
- if (!e)
- return NULL;
+ if (!e) {
+ errno = -ENOENT;
+ return -ENOENT;
+ }
+
if (e != mtab)
pathname += strlen(e->path);
@@ -265,37 +444,8 @@ int mkdir (const char *pathname)
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;
+ errno = -EROFS;
+ return -EROFS;
}
-U_BOOT_CMD(
- mkdir, 2, 0, do_mkdir,
- "mkdir - create a new directory\n",
- ""
-);
-
-U_BOOT_CMD(
- 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(
- delfs, 2, 0, do_delfs,
- "delfs - delete a filesystem from a device\n",
- ""
-);
-#endif
diff --git a/fs/ramfs.c b/fs/ramfs.c
index 7d3d2b6735..d271b27bf9 100644
--- a/fs/ramfs.c
+++ b/fs/ramfs.c
@@ -8,13 +8,6 @@
#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;
@@ -32,19 +25,6 @@ struct node_d {
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;
};
@@ -88,36 +68,6 @@ out:
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));
@@ -192,9 +142,9 @@ int ramfs_probe(struct device_d *dev)
return 0;
}
-static struct handle_d *ramfs_open(struct device_d *dev, const char *pathname)
+static int ramfs_open(struct device_d *_dev, FILE *file, const char *filename)
{
- return NULL;
+ return -ENOENT;
}
struct dir* ramfs_opendir(struct device_d *dev, const char *pathname)
@@ -222,7 +172,6 @@ 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;
}
@@ -235,6 +184,21 @@ int ramfs_closedir(struct device_d *dev, struct dir *dir)
return 0;
}
+int ramfs_stat(struct device_d *dev, const char *filename, struct stat *s)
+{
+ struct ramfs_priv *priv = dev->priv;
+ struct node_d *node = rlookup(&priv->root, filename);
+
+ if (!node) {
+ errno = -ENOENT;
+ return -ENOENT;
+ }
+
+ s->st_mode = node->mode;
+
+ return 0;
+}
+
static struct fs_driver_d ramfs_driver = {
.type = FS_TYPE_RAMFS,
.create = ramfs_create,
@@ -245,6 +209,7 @@ static struct fs_driver_d ramfs_driver = {
.opendir = ramfs_opendir,
.readdir = ramfs_readdir,
.closedir = ramfs_closedir,
+ .stat = ramfs_stat,
.flags = FS_DRIVER_NO_DEV,
.drv = {
@@ -262,21 +227,3 @@ int ramfs_init(void)
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"
-);
-
diff --git a/include/common.h b/include/common.h
index c45850169d..d1f9cdc292 100644
--- a/include/common.h
+++ b/include/common.h
@@ -593,7 +593,7 @@ void vprintf(const char *fmt, va_list args);
#define stdin 0
#define stdout 1
#define stderr 2
-#define MAX_FILES 3
+#define MAX_FILES 16
void fprintf(int file, const char *fmt, ...);
void fputs(int file, const char *s);
diff --git a/include/driver.h b/include/driver.h
index c7ede1acc7..a37a7cd0bb 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -48,6 +48,7 @@ struct driver_d {
struct driver_d *next;
int (*probe) (struct device_d *);
+ int (*remove)(struct device_d *);
ssize_t (*read) (struct device_d*, void* buf, size_t count, ulong offset, ulong flags);
ssize_t (*write) (struct device_d*, void* buf, size_t count, ulong offset, ulong flags);
ssize_t (*erase) (struct device_d*, size_t count, unsigned long offset);
@@ -74,13 +75,13 @@ void unregister_device(struct device_d *);
struct device_d *device_from_spec_str(const char *str, char **endp);
struct device_d *get_device_by_name(char *name);
struct device_d *get_device_by_type(ulong type, struct device_d *last);
-struct device_d *get_device_by_id(char *id);
+struct device_d *get_device_by_id(const char *id);
struct driver_d *get_driver_by_name(char *name);
-ssize_t read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
-ssize_t write(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
-ssize_t erase(struct device_d *dev, size_t count, unsigned long offset);
+ssize_t dev_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
+ssize_t dev_write(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
+ssize_t dev_erase(struct device_d *dev, size_t count, unsigned long offset);
ssize_t mem_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
ssize_t mem_write(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
diff --git a/include/errno.h b/include/errno.h
index aee5c78fff..56ed0ed9d9 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -1,6 +1,8 @@
#ifndef __ERRNO_H
#define __ERRNO_H
-void perror(const char *s, int errno);
+extern int errno;
+
+void perror(const char *s);
#endif /* __ERRNO_H */
diff --git a/include/fs.h b/include/fs.h
index c600a9dd95..22e5fcf07e 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -10,10 +10,9 @@
struct partition;
struct node_d;
+struct stat;
struct dirent {
- unsigned long mode;
- unsigned long size;
char name[256];
};
@@ -25,20 +24,32 @@ struct dir {
void *priv; /* private data for the fs driver */
};
+typedef struct filep {
+ struct device_d *dev;
+ ulong pos;
+ char used;
+ int no;
+ void *inode; /* private to the filesystem driver */
+} FILE;
+
#define FS_DRIVER_NO_DEV 1
struct fs_driver_d {
ulong type;
char *name;
- 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);
+
+ 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);
+ int (*write)(struct device_d *dev, FILE *f, void *buf, size_t size);
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);
+ int (*stat)(struct device_d *dev, const char *file, struct stat *stat);
struct driver_d drv;
@@ -52,11 +63,29 @@ struct fs_device_d {
struct fs_driver_d *driver;
};
-int register_filesystem(struct device_d *dev, char *fsname);
-//int unregister_filesystem(struct device_d *dev);
+int open(const char *pathname, int flags);
+int close(int fd);
+int read(int fd, void *buf, size_t count);
+ssize_t write(int fd, const void *buf, size_t count);
+int ls(const char *path);
+int mkdir (const char *pathname);
+int mount (struct device_d *dev, char *fsname, char *path);
+int umount(const char *pathname);
-int register_fs_driver(struct fs_driver_d *new_fs_drv);
+struct dir *opendir(const char *pathname);
+struct dirent *readdir(struct dir *dir);
+int closedir(struct dir *dir);
char *mkmodestr(unsigned long mode, char *str);
+struct mtab_entry *get_mtab_entry_by_path(const char *path);
+
+struct mtab_entry {
+ char path[PATH_MAX];
+ struct mtab_entry *next;
+ struct device_d *dev;
+};
+
+void normalise_path(char *path);
+
#endif /* __FS_H */
diff --git a/lib_generic/misc.c b/lib_generic/misc.c
index 6df4f5c15c..92a8374a16 100644
--- a/lib_generic/misc.c
+++ b/lib_generic/misc.c
@@ -5,6 +5,7 @@
#include <init.h>
#include <malloc.h>
#include <linux/ctype.h>
+#include <errno.h>
#include <asm-generic/errno.h>
int cmd_get_data_size(char* arg, int default_size)
@@ -32,7 +33,7 @@ int cmd_get_data_size(char* arg, int default_size)
static struct device_d *first_device = NULL;
static struct driver_d *first_driver = NULL;
-struct device_d *get_device_by_id(char *id)
+struct device_d *get_device_by_id(const char *id)
{
struct device_d *d;
@@ -357,25 +358,28 @@ out:
return 0;
}
-ssize_t read(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
+ssize_t dev_read(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
{
if (dev->driver->read)
return dev->driver->read(dev, buf, count, offset, flags);
- return -1;
+ errno = -ENOSYS;
+ return -ENOSYS;
}
-ssize_t write(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
+ssize_t dev_write(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
{
if (dev->driver->write)
return dev->driver->write(dev, buf, count, offset, flags);
- return -1;
+ errno = -ENOSYS;
+ return -ENOSYS;
}
-ssize_t erase(struct device_d *dev, size_t count, unsigned long offset)
+ssize_t dev_erase(struct device_d *dev, size_t count, unsigned long offset)
{
if (dev->driver->erase)
return dev->driver->erase(dev, count, offset);
- return -1;
+ errno = -ENOSYS;
+ return -ENOSYS;
}
int dummy_probe(struct device_d *dev)
@@ -414,7 +418,12 @@ struct param_d* dev_get_param(struct device_d *dev, char *name)
{
struct param_d *param = get_param_by_name(dev, name);
- if (param && param->get)
+ if (!param) {
+ errno = -EINVAL;
+ return NULL;
+ }
+
+ if (param->get)
return param->get(dev, param);
return param;
@@ -424,8 +433,10 @@ IPaddr_t dev_get_param_ip(struct device_d *dev, char *name)
{
struct param_d *param = dev_get_param(dev, name);
- if (!param || param->type != PARAM_TYPE_IPADDR)
- return -1;
+ if (!param || param->type != PARAM_TYPE_IPADDR) {
+ errno = -EINVAL;
+ return 0;
+ }
return param->value.val_ip;
}
@@ -443,11 +454,15 @@ int dev_set_param(struct device_d *dev, char *name, value_t val)
{
struct param_d *param = get_param_by_name(dev, name);
- if (!param)
+ if (!param) {
+ errno = -EINVAL;
return -EINVAL;
+ }
- if (param->flags & PARAM_FLAG_RO)
+ if (param->flags & PARAM_FLAG_RO) {
+ errno = -EACCES;
return -EACCES;
+ }
if (param->set)
return param->set(dev, param, val);
diff --git a/net/tftp.c b/net/tftp.c
index ba1ececc0d..e58b38030d 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -65,7 +65,7 @@ store_block (unsigned block, uchar * src, unsigned len)
ulong offset = block * TFTP_BLOCK_SIZE + TftpBlockWrapOffset;
ulong newsize = offset + len;
- write(net_store_mem.device, src, len, net_store_mem.start + offset, 0);
+ dev_write(net_store_mem.device, src, len, net_store_mem.start + offset, 0);
if (NetBootFileXferSize < newsize)
NetBootFileXferSize = newsize;