From 9ba6638d017b84107222a73701d9677bb8bb6ae8 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Tue, 15 Apr 2008 19:36:07 +0100 Subject: [PATCH] Added new path parsing functions that work cleaner, better. Input paths are now parsed at the beginning and components put into an ordered linked list headed by struct pathdata. Lookup functions use these components to look up vnodes. --- tasks/fs0/include/path.h | 17 +++++- tasks/fs0/include/vfs.h | 2 +- tasks/fs0/src/lookup.c | 57 ++------------------ tasks/fs0/src/path.c | 112 +++++++++++++++++++++++++++++++++++++++ tasks/fs0/src/syscalls.c | 65 +++++++++++++---------- tasks/fs0/src/vfs.c | 8 +-- 6 files changed, 176 insertions(+), 85 deletions(-) create mode 100644 tasks/fs0/src/path.c diff --git a/tasks/fs0/include/path.h b/tasks/fs0/include/path.h index fa86b97..8101f4e 100644 --- a/tasks/fs0/include/path.h +++ b/tasks/fs0/include/path.h @@ -6,6 +6,8 @@ #ifndef __PATH_H__ #define __PATH_H__ +#include + /* * FIXME: * These ought to be strings and split/comparison functions should @@ -18,9 +20,22 @@ #define VFS_STR_XATDIR "...." struct pathdata { + struct list_head list; struct tcb *task; int root; - char *path; }; +struct pathcomp { + struct list_head list; + char *str; +}; + +struct pathdata *pathdata_parse(const char *pathname, char *pathbuf, + struct tcb *task); +void pathdata_destroy(struct pathdata *p); + +/* Destructive, i.e. unlinks those components from list */ +char *pathdata_next_component(struct pathdata *pdata); +char *pathdata_last_component(struct pathdata *pdata); + #endif /* __PATH_H__ */ diff --git a/tasks/fs0/include/vfs.h b/tasks/fs0/include/vfs.h index 6000f82..2d24346 100644 --- a/tasks/fs0/include/vfs.h +++ b/tasks/fs0/include/vfs.h @@ -83,7 +83,7 @@ extern struct vfs_mountpoint vfs_root; int vfs_mount_root(struct superblock *sb); struct vnode *generic_vnode_lookup(struct vnode *thisnode, struct pathdata *p); -struct vnode *vfs_lookup_bypath(struct tcb *task, struct pathdata *p); +struct vnode *vfs_lookup_bypath(struct pathdata *p); struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum); #endif /* __VFS_H__ */ diff --git a/tasks/fs0/src/lookup.c b/tasks/fs0/src/lookup.c index 2b71d21..b5b02d3 100644 --- a/tasks/fs0/src/lookup.c +++ b/tasks/fs0/src/lookup.c @@ -8,6 +8,7 @@ #include #include #include +#include /* * Given a dentry that has been populated by readdir with children dentries @@ -29,41 +30,6 @@ struct vnode *lookup_dentry_children(struct dentry *parentdir, return PTR_ERR(-ENOENT); } -/* - * Check if we're really at root, return root string if so, and - * move the pdata string cursor to next component or the end of string. - */ -char *pathdata_handle_root(struct pathdata *pdata) -{ - char *cursor = pdata->path; - - /* Only handle if root */ - if (!pdata->root) - return 0; - - /* Move forward until no seperator */ - while (*cursor == VFS_CHAR_SEP) { - *cursor = '\0'; /* Zero out separators */ - cursor++; /* Move to next */ - } - - /* - * Moved the cursor either to first char of - * next component, or the end of string - * (in which case cursor = '\0') - */ - pdata->path = cursor; - - /* We have handled the root case, now turn it off */ - pdata->root = 0; - - /* - * Modified pdata appropriately, return the root - * component. It's the root representer string, e.g. "/" - */ - return VFS_STR_ROOTDIR; -} - /* Lookup, recursive, assuming single-mountpoint */ struct vnode *generic_vnode_lookup(struct vnode *thisnode, struct pathdata *pdata) @@ -73,22 +39,7 @@ struct vnode *generic_vnode_lookup(struct vnode *thisnode, struct vnode *found; int err; - /* - * Determine first component, taking root as special case. - * - * path (root = 0) -> first path component - * path (root = 1) -> VFS_STR_ROOTDIR - * where path = { "//comp1/comp2", "/", "/comp1/comp2", "comp1/comp2" } - */ - - printf("Looking up: %s\n", pdata->path); - - /* Handle the special root case */ - if (pdata->root) - component = pathdata_handle_root(pdata); - /* Handle paths normally */ - else - component = splitpath(&pdata->path, VFS_CHAR_SEP); + component = pathdata_next_component(pdata); /* Does this path component match with any of this vnode's dentries? */ list_for_each_entry(d, &thisnode->dentries, vref) { @@ -96,7 +47,7 @@ struct vnode *generic_vnode_lookup(struct vnode *thisnode, /* Is this a directory? */ if (vfs_isdir(thisnode)) { /* Are there any more path components? */ - if (*pdata->path) { + if (!list_empty(&pdata->list)) { /* Read directory contents */ if ((err = d->vnode->ops.readdir(d->vnode)) < 0) return PTR_ERR(err); @@ -108,7 +59,7 @@ struct vnode *generic_vnode_lookup(struct vnode *thisnode, } else return thisnode; } else { /* Its a file */ - if (*pdata->path) /* There's still path, but not directory */ + if (!list_empty(&pdata->list)) /* There's still path, but not directory */ return PTR_ERR(-ENOTDIR); else /* No path left, found it, so return file */ return thisnode; diff --git a/tasks/fs0/src/path.c b/tasks/fs0/src/path.c new file mode 100644 index 0000000..bb5ff87 --- /dev/null +++ b/tasks/fs0/src/path.c @@ -0,0 +1,112 @@ +/* + * Path manipulation functions. + * + * Copyright (C) 2008 Bahadir Balban + */ +#include +#include +#include +#include +#include +#include +#include + +char *pathdata_next_component(struct pathdata *pdata) +{ + struct pathcomp *p, *n; + char *pathstr; + + list_for_each_entry_safe(p, n, &pdata->list, list) { + list_del(&p->list); + pathstr = p->str; + kfree(p); + return pathstr; + } + return ""; +} + +/* Check there's at least one element, unlink and return the last element */ +char *pathdata_last_component(struct pathdata *pdata) +{ + struct pathcomp *p; + char *pathstr; + + if (!list_empty(&pdata->list)) { + p = list_entry(pdata->list.prev, struct pathcomp, list); + list_del(&p->list); + pathstr = p->str; + kfree(p); + return pathstr; + } + + return ""; +} + +/* Unlink and free all path components in pathdata, and then free pathdata */ +void pathdata_destroy(struct pathdata *p) +{ + struct pathcomp *c, *n; + + list_for_each_entry_safe(c, n, &p->list, list) { + list_del(&c->list); + kfree(c); + } + kfree(p); +} + +void pathdata_print(struct pathdata *p) +{ + struct pathcomp *comp; + + printf("Extracted path is:\n"); + list_for_each_entry(comp, &p->list, list) + printf("%s\n", comp->str); +} + +/* Extracts all path components from pathname into more presentable form */ +struct pathdata *pathdata_parse(const char *pathname, + char *pathbuf, struct tcb *task) +{ + struct pathdata *pdata = kzalloc(sizeof(*pdata)); + struct pathcomp *comp; + char *str; + + if (!pdata) + return PTR_ERR(-ENOMEM); + + /* Initialise pathdata */ + INIT_LIST_HEAD(&pdata->list); + strcpy(pathbuf, pathname); + pdata->task = task; + + /* Handle root if there's a root */ + if (pathname[0] == VFS_CHAR_SEP) { + if (!(comp = kzalloc(sizeof(*comp)))) { + kfree(pdata); + return PTR_ERR(-ENOMEM); + } + INIT_LIST_HEAD(&comp->list); + comp->str = VFS_STR_ROOTDIR; + list_add_tail(&comp->list, &pdata->list); + pdata->root = 1; + } + + /* Add every other path component */ + str = splitpath(&pathbuf, VFS_CHAR_SEP); + while(*str) { + if (!(comp = kzalloc(sizeof(*comp)))) { + pathdata_destroy(pdata); + return PTR_ERR(-ENOMEM); + } + INIT_LIST_HEAD(&comp->list); + comp->str = str; + list_add_tail(&comp->list, &pdata->list); + + /* Next component */ + str = splitpath(&pathbuf, VFS_CHAR_SEP); + } + // pathdata_print(pdata); + + return pdata; +} + diff --git a/tasks/fs0/src/syscalls.c b/tasks/fs0/src/syscalls.c index 9d8d051..af397c9 100644 --- a/tasks/fs0/src/syscalls.c +++ b/tasks/fs0/src/syscalls.c @@ -16,6 +16,7 @@ #include #include #include +#include /* * This notifies mm0 that this is the fd that refers to this vnode number @@ -49,12 +50,11 @@ int vfs_create(struct tcb *task, struct pathdata *pdata, unsigned int mode) char *nodename; int err; - printf("%s: %s\n", __FUNCTION__, pdata->path); /* The last component is to be created */ - nodename = splitpath_end(&pdata->path, '/'); + nodename = pathdata_last_component(pdata); /* Check that the parent directory exists. */ - if (IS_ERR(vparent = vfs_lookup_bypath(task, pdata))) + if (IS_ERR(vparent = vfs_lookup_bypath(pdata))) return (int)vparent; /* The parent vnode must be a directory. */ @@ -68,17 +68,6 @@ int vfs_create(struct tcb *task, struct pathdata *pdata, unsigned int mode) return 0; } -void init_path_data(struct pathdata *pdata, const char *pathname, - void *pathbuf, struct tcb *task) -{ - pdata->path = pathbuf; - strcpy(pdata->path, pathname); - pdata->task = task; - - if (pdata->path[0] == '/') - pdata->root = 1; -} - /* FIXME: * - Is it already open? * - Allocate a copy of path string since lookup destroys it @@ -86,7 +75,7 @@ void init_path_data(struct pathdata *pdata, const char *pathname, */ int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode) { - struct pathdata pdata; + struct pathdata *pdata; struct vnode *v; struct tcb *task; int fd; @@ -95,16 +84,21 @@ int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode) /* Get the task */ BUG_ON(!(task = find_task(sender))); - /* Initialise pdata */ - init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task); + /* Parse path data */ + if (IS_ERR(pdata = pathdata_parse(pathname, + alloca(strlen(pathname) + 1), + task))) { + l4_ipc_return((int)pdata); + return 0; + } /* Get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(task, &pdata))) { + if (IS_ERR(v = vfs_lookup_bypath(pdata))) { if (!(flags & O_CREAT)) { l4_ipc_return((int)v); return 0; } else { - if ((err = vfs_create(task, &pdata, mode)) < 0) { + if ((err = vfs_create(task, pdata, mode)) < 0) { l4_ipc_return(err); return 0; } @@ -120,6 +114,7 @@ int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode) /* Tell the pager about opened vnode information */ BUG_ON(pager_sys_open(sender, fd, v->vnum, v->size) < 0); + pathdata_destroy(pdata); l4_ipc_return(0); return 0; } @@ -132,15 +127,24 @@ int sys_close(l4id_t sender, int fd) int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode) { struct tcb *task; - struct pathdata pdata; + struct pathdata *pdata; /* Get the task */ BUG_ON(!(task = find_task(sender))); - /* Init path data */ - init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task); + /* Parse path data */ + if (IS_ERR(pdata = pathdata_parse(pathname, + alloca(strlen(pathname) + 1), + task))) { + l4_ipc_return((int)pdata); + return 0; + } - l4_ipc_return(vfs_create(task, &pdata, mode)); + /* Create the directory or fail */ + l4_ipc_return(vfs_create(task, pdata, mode)); + + /* Destroy extracted path data */ + pathdata_destroy(pdata); return 0; } @@ -148,16 +152,21 @@ int sys_chdir(l4id_t sender, const char *pathname) { struct vnode *v; struct tcb *task; - struct pathdata pdata; + struct pathdata *pdata; /* Get the task */ BUG_ON(!(task = find_task(sender))); - /* Init path data */ - init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task); + /* Parse path data */ + if (IS_ERR(pdata = pathdata_parse(pathname, + alloca(strlen(pathname) + 1), + task))) { + l4_ipc_return((int)pdata); + return 0; + } /* Get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(task, &pdata))) + if (IS_ERR(v = vfs_lookup_bypath(pdata))) return (int)v; /* Ensure it's a directory */ @@ -167,6 +176,8 @@ int sys_chdir(l4id_t sender, const char *pathname) /* Assign the current directory pointer */ task->curdir = v; + /* Destroy extracted path data */ + pathdata_destroy(pdata); return 0; } diff --git a/tasks/fs0/src/vfs.c b/tasks/fs0/src/vfs.c index aa42f72..b9985b8 100644 --- a/tasks/fs0/src/vfs.c +++ b/tasks/fs0/src/vfs.c @@ -6,6 +6,7 @@ #include #include #include +#include LIST_HEAD(vnode_cache); LIST_HEAD(dentry_cache); @@ -57,19 +58,20 @@ struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum) * have, the other is their vnum. This one checks the vnode cache by the path * first. If nothing is found, it reads the vnode from disk into the cache. */ -struct vnode *vfs_lookup_bypath(struct tcb *task, struct pathdata *pdata) +struct vnode *vfs_lookup_bypath(struct pathdata *pdata) { struct vnode *vstart; /* Do we start from root or curdir? */ if (pdata->root) - vstart = task->rootdir; + vstart = pdata->task->rootdir; else - vstart = task->curdir; + vstart = pdata->task->curdir; /* * This does vfs cache + fs lookup. */ + BUG_ON(list_empty(&pdata->list)); return vstart->ops.lookup(vstart, pdata); }