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.
This commit is contained in:
Bahadir Balban
2008-04-15 19:36:07 +01:00
parent fb249b0c5b
commit 9ba6638d01
6 changed files with 176 additions and 85 deletions

View File

@@ -6,6 +6,8 @@
#ifndef __PATH_H__
#define __PATH_H__
#include <l4/lib/list.h>
/*
* 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__ */

View File

@@ -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__ */

View File

@@ -8,6 +8,7 @@
#include <stat.h>
#include <l4/api/errno.h>
#include <lib/pathstr.h>
#include <path.h>
/*
* 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;

112
tasks/fs0/src/path.c Normal file
View File

@@ -0,0 +1,112 @@
/*
* Path manipulation functions.
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <l4/macros.h>
#include <l4/lib/list.h>
#include <l4/api/errno.h>
#include <lib/pathstr.h>
#include <lib/malloc.h>
#include <path.h>
#include <stdio.h>
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;
}

View File

@@ -16,6 +16,7 @@
#include <stat.h>
#include <vfs.h>
#include <alloca.h>
#include <path.h>
/*
* 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;
}

View File

@@ -6,6 +6,7 @@
#include <fs.h>
#include <vfs.h>
#include <task.h>
#include <path.h>
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);
}