mkdir almost working.

Added changes to pathname lookup code so that the root
directory special case is handled properly.
This commit is contained in:
Bahadir Balban
2008-04-15 00:51:58 +01:00
parent 287b7705da
commit a9420d3dc9
11 changed files with 159 additions and 66 deletions

View File

@@ -10,7 +10,7 @@
#include <l4/macros.h>
#include <l4lib/types.h>
#include <stat.h>
#include <path.h>
typedef void (*vnode_op_t)(void);
typedef void (*file_op_t)(void);
@@ -46,7 +46,7 @@ struct file_ops {
/* Operations that work on vnode fields and associations between vnodes */
struct vnode_ops {
vnode_op_t create;
struct vnode *(*lookup)(struct vnode *root, char *path);
struct vnode *(*lookup)(struct vnode *root, struct pathdata *pdata);
int (*readdir)(struct vnode *v);
int (*filldir)(void *buf, struct vnode *v, int count);
vnode_op_t link;

26
tasks/fs0/include/path.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2008 Bahadir Balban
*
* Path lookup related information
*/
#ifndef __PATH_H__
#define __PATH_H__
/*
* FIXME:
* These ought to be strings and split/comparison functions should
* always use strings because formats like UTF-8 wouldn't work.
*/
#define VFS_CHAR_SEP '/'
#define VFS_STR_ROOTDIR "/"
#define VFS_STR_PARDIR ".."
#define VFS_STR_CURDIR "."
#define VFS_STR_XATDIR "...."
struct pathdata {
struct tcb *task;
int root;
char *path;
};
#endif /* __PATH_H__ */

View File

@@ -8,20 +8,11 @@
#include <l4/macros.h>
#include <stdio.h>
#include <task.h>
#include <path.h>
extern struct list_head vnode_cache;
extern struct list_head dentry_cache;
/*
* FIXME:
* These ought to be strings and split/comparison functions should
* always use strings because formats like UTF-8 wouldn't work.
*/
#define VFS_STR_SEP '/'
#define VFS_STR_PARDIR ".."
#define VFS_STR_CURDIR "."
#define VFS_STR_XATDIR "...."
/*
* This is a temporary replacement for page cache support provided by mm0.
* Normally mm0 tracks all vnode pages, but this is used to track pages in
@@ -91,8 +82,8 @@ struct vfs_mountpoint {
extern struct vfs_mountpoint vfs_root;
int vfs_mount_root(struct superblock *sb);
struct vnode *generic_vnode_lookup(struct vnode *thisnode, char *path);
struct vnode *vfs_lookup_bypath(struct tcb *task, char *path);
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_byvnum(struct superblock *sb, unsigned long vnum);
#endif /* __VFS_H__ */

View File

@@ -31,10 +31,6 @@ char *splitpath(char **str, char sep)
char *cursor = *str;
char *end;
/* Root is the special case, return it as is. */
if (strcmp(*str, "/"))
return *str;
/* Move forward until no seperator */
while (*cursor == sep) {
*cursor = '\0';

View File

@@ -14,47 +14,99 @@
* and their vnodes, this itself checks all those children on that level for
* a match, but it also calls lookup, which recursively checks lower levels.
*/
struct vnode *lookup_dentry_children(struct dentry *parentdir, char *path)
struct vnode *lookup_dentry_children(struct dentry *parentdir,
struct pathdata *pdata)
{
struct dentry *childdir;
struct vnode *v;
list_for_each_entry(childdir, &parentdir->children, child)
/* Non-zero result means either found it or error occured */
if ((v = childdir->vnode->ops.lookup(childdir->vnode, path)))
if ((v = childdir->vnode->ops.lookup(childdir->vnode, pdata)))
return v;
/* Out of all children dentries, neither was a match, so we return 0 */
return PTR_ERR(-ENOENT);
}
/* Lookup, recursive, assuming single-mountpoint */
struct vnode *generic_vnode_lookup(struct vnode *thisnode, char *path)
/*
* 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 *component = splitpath(&path, VFS_STR_SEP);
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)
{
char *component;
struct dentry *d;
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" }
*/
/* Handle the special root case */
if (pdata->root)
component = pathdata_handle_root(pdata);
/* Handle paths normally */
else
component = splitpath(&pdata->path, VFS_CHAR_SEP);
/* Does this path component match with any of this vnode's dentries? */
list_for_each_entry(d, &thisnode->dentries, vref) {
if (d->ops.compare(d, component)) {
/* Is this a directory? */
if (vfs_isdir(thisnode)) {
/* Are there any more path components? */
if (path) {
if (*pdata->path) {
/* Read directory contents */
if ((err = d->vnode->ops.readdir(d->vnode)) < 0)
return PTR_ERR(err);
/* Search all children one level below. */
if ((found = lookup_dentry_children(d, path)))
if ((found = lookup_dentry_children(d, pdata)))
/* Either found, or non-zero error */
return found;
} else
return thisnode;
} else { /* Its a file */
if (path) /* There's still path, but not directory */
if (*pdata->path) /* There's still path, but not directory */
return PTR_ERR(-ENOTDIR);
else /* No path left, found it, so return file */
return thisnode;
@@ -68,7 +120,7 @@ struct vnode *generic_vnode_lookup(struct vnode *thisnode, char *path)
int generic_dentry_compare(struct dentry *d, char *name)
{
if (!strcmp(d->name, name))
if (!strcmp(d->name, name) || !strcmp(name, VFS_STR_CURDIR))
return 1;
else
return 0;

View File

@@ -93,7 +93,7 @@ int memfs_file_read_write(struct vnode *v, unsigned int pfn,
} else { /* Write-specific operations */
/* Is the write beyond current file size? */
if (v->size < ((pfn + npages) * (blocksize))) {
unsigned long diff = pfn + npages - __pfn(v->size);
unsigned long pagediff = pfn + npages - __pfn(v->size);
unsigned long holes;
/*
@@ -102,19 +102,18 @@ int memfs_file_read_write(struct vnode *v, unsigned int pfn,
*/
if (pfn > __pfn(v->size))
holes = pfn - __pfn(v->size);
else
holes = 0;
/* Allocate new blocks */
for (int x = 0; x < diff; x++)
if (!(i->block[__pfn(v->size) + x] = memfs_alloc_block(memfs_sb)))
for (int x = 0; x < pagediff; x++)
if (!(i->block[__pfn(v->size) + x] =
memfs_alloc_block(v->sb->fs_super)))
return -ENOSPC;
/* Zero out the holes. FIXME: How do we zero out non-page-aligned bytes?` */
for (int x = 0; x < holes; x++)
memset(i->block[__pfn(v->size) + x], 0, blocksize);
/* Update size and the inode. FIXME: How do we handle non page-aligned size */
v->size = (pfn + npages) * blocksize;
v->sb->ops->write_vnode(v->sb, v);
}
/* Copy the data from page buffer into inode blocks */

View File

@@ -135,8 +135,13 @@ int memfs_init_rootdir(struct superblock *sb)
if (!(d = vfs_alloc_dentry()))
return -ENOMEM;
/* Initialise it. NOTE: On root, parent is itself */
strncpy(d->name, "/", VFS_DNAME_MAX);
/*
* Initialise it.
* NOTE: On root, parent is itself.
* NOTE: Root has no name. This helps since splitpath
* cuts out the '/' and "" is left for root name search.
*/
strncpy(d->name, VFS_STR_ROOTDIR, VFS_DNAME_MAX);
d->ops = generic_dentry_operations;
d->parent = d;
d->vnode = v;

View File

@@ -228,8 +228,6 @@ int memfs_vnode_mknod(struct vnode *v, char *dirname, unsigned int mode)
BUG_ON(parent->vref.next != &v->dentries);
BUG_ON(!vfs_isdir(v));
printf("Parent name: %s\n", parent->name);
/* Populate the children */
if ((err = v->ops.readdir(v)) < 0)
return err;
@@ -263,8 +261,9 @@ int memfs_vnode_mknod(struct vnode *v, char *dirname, unsigned int mode)
/* Write the updated directory buffer back to disk block */
v->fops.write(v, 0, 1, v->dirbuf.buffer);
/* Update parent vnode */
/* Update parent vnode size */
v->size += sizeof(*memfsd);
v->sb->ops->write_vnode(v->sb, v);
/* Allocate a new vfs dentry */
if (!(newd = vfs_alloc_dentry()))
@@ -382,7 +381,10 @@ int memfs_vnode_readdir(struct vnode *v)
return 0;
}
/*
* Copies fs-specific dirent data into user buffer in
* generic struct dirent format.
*/
int memfs_vnode_filldir(void *userbuf, struct vnode *v, int count)
{
int nbytes;
@@ -412,6 +414,7 @@ struct vnode_ops memfs_vnode_operations = {
.readdir = memfs_vnode_readdir,
.filldir = memfs_vnode_filldir,
.mknod = memfs_vnode_mknod,
.lookup = generic_vnode_lookup,
};
struct superblock_ops memfs_superblock_operations = {

View File

@@ -43,21 +43,17 @@ int pager_sys_open(l4id_t sender, int fd, unsigned long vnum, unsigned long size
}
/* Creates a node under a directory, e.g. a file, directory. */
int vfs_create(struct tcb *task, const char *pathname, unsigned int mode)
int vfs_create(struct tcb *task, struct pathdata *pdata, unsigned int mode)
{
char *pathbuf = alloca(strlen(pathname) + 1);
char *parentpath = pathbuf;
struct vnode *vparent;
char *nodename;
int err;
strcpy(pathbuf, pathname);
/* The last component is to be created */
nodename = splitpath_end(&parentpath, '/');
nodename = splitpath_end(&pdata->path, '/');
/* Check that the parent directory exists. */
if (IS_ERR(vparent = vfs_lookup_bypath(task, parentpath)))
if (IS_ERR(vparent = vfs_lookup_bypath(task, pdata)))
return (int)vparent;
/* The parent vnode must be a directory. */
@@ -71,6 +67,17 @@ int vfs_create(struct tcb *task, const char *pathname, 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
@@ -78,24 +85,25 @@ int vfs_create(struct tcb *task, const char *pathname, unsigned int mode)
*/
int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
{
char *pathbuf = alloca(strlen(pathname) + 1);
struct pathdata pdata;
struct vnode *v;
struct tcb *task;
int fd;
int err;
strcpy(pathbuf, pathname);
/* Get the task */
BUG_ON(!(task = find_task(sender)));
/* Initialise pdata */
init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task);
/* Get the vnode */
if (IS_ERR(v = vfs_lookup_bypath(task, pathbuf))) {
if (IS_ERR(v = vfs_lookup_bypath(task, &pdata))) {
if (!(flags & O_CREAT)) {
l4_ipc_return((int)v);
return 0;
} else {
if ((err = vfs_create(task, pathname, mode)) < 0) {
if ((err = vfs_create(task, &pdata, mode)) < 0) {
l4_ipc_return(err);
return 0;
}
@@ -123,27 +131,32 @@ 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;
/* Get the task */
BUG_ON(!(task = find_task(sender)));
l4_ipc_return(vfs_create(task, pathname, mode));
/* Init path data */
init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task);
l4_ipc_return(vfs_create(task, &pdata, mode));
return 0;
}
int sys_chdir(l4id_t sender, const char *pathname)
{
char *pathbuf = alloca(strlen(pathname) + 1);
struct vnode *v;
struct tcb *task;
strcpy(pathbuf, pathname);
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);
/* Get the vnode */
if (IS_ERR(v = vfs_lookup_bypath(task, pathbuf)))
if (IS_ERR(v = vfs_lookup_bypath(task, &pdata)))
return (int)v;
/* Ensure it's a directory */

View File

@@ -57,18 +57,12 @@ 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, char *path)
struct vnode *vfs_lookup_bypath(struct tcb *task, struct pathdata *pdata)
{
struct vnode *vstart;
/* Is it the root or current directory? If so, we already got it. */
if (!strcmp(path, "/"))
return task->rootdir;
if (!strcmp(path, "."))
return task->curdir;
/* Do we start from root or curdir? */
if (path[0] == '/')
if (pdata->root)
vstart = task->rootdir;
else
vstart = task->curdir;
@@ -76,7 +70,7 @@ struct vnode *vfs_lookup_bypath(struct tcb *task, char *path)
/*
* This does vfs cache + fs lookup.
*/
return generic_vnode_lookup(vstart, path);
return vstart->ops.lookup(vstart, pdata);
}
int vfs_mount_root(struct superblock *sb)

View File

@@ -136,6 +136,20 @@ int dirtest(void)
printf("\nCreating directories: usr, etc, tmp, var, home, opt, bin, boot, lib, dev\n");
if (mkdir("/usr", 0) < 0)
perror("MKDIR");
if (mkdir("/etc", 0) < 0)
perror("MKDIR");
if (mkdir("/tmp", 0) < 0)
perror("MKDIR");
if (mkdir("/var", 0) < 0)
perror("MKDIR");
if (mkdir("/bin", 0) < 0)
perror("MKDIR");
if (mkdir("/boot", 0) < 0)
perror("MKDIR");
if (mkdir("/lib", 0) < 0)
perror("MKDIR");
if (mkdir("/dev", 0) < 0)
perror("MKDIR");
printf("\nlsdir root directory:\n");
lsdir("/");