mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
mkdir almost working.
Added changes to pathname lookup code so that the root directory special case is handled properly.
This commit is contained in:
@@ -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
26
tasks/fs0/include/path.h
Normal 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__ */
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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("/");
|
||||
|
||||
Reference in New Issue
Block a user