Added sys_mkdir and memfs_vnode_mkdir() functions. Untested but all implemented.

This commit is contained in:
Bahadir Balban
2008-02-15 17:32:41 +00:00
parent 5de93f707c
commit 09bd001e1a
6 changed files with 221 additions and 56 deletions

View File

@@ -50,7 +50,7 @@ struct vnode_ops {
int (*readdir)(struct vnode *v);
vnode_op_t link;
vnode_op_t unlink;
vnode_op_t mkdir;
int (*mkdir)(struct vnode *parent, char *name);
vnode_op_t rmdir;
vnode_op_t rename;
vnode_op_t getattr;
@@ -109,8 +109,7 @@ struct vnode {
struct list_head dentries; /* Dirents that refer to this vnode */
struct list_head cache_list; /* For adding the vnode to vnode cache */
struct dirbuf dirbuf; /* Only directory buffers are kept */
u32 type; /* Vnode type, dev? socket? dir? ... */
u32 mode; /* Permissions */
u32 mode; /* Permissions and vnode type */
u32 owner; /* Owner */
u64 atime; /* Last access time */
u64 mtime; /* Last content modification */
@@ -120,7 +119,12 @@ struct vnode {
};
/* FS0 vfs specific macros */
#define vfs_isdir(v) S_ISDIR((v)->type)
/* Check if directory */
#define vfs_isdir(v) S_ISDIR((v)->mode)
/* Set vnode type */
#define vfs_set_type(v, type) {v->mode &= ~S_IFMT; v->mode |= S_IFMT & type; }
struct fstype_ops {
struct superblock *(*get_superblock)(void *buf);

View File

@@ -0,0 +1,9 @@
#ifndef __LIB_PATHSTR_H__
#define __LIB_PATHSTR_H__
char *strreverse(char *str);
char *splitpath_end(char **path, char sep);
char *splitpath(char **str, char sep);
#endif /* __LIB_PATHSTR_H__ */

View File

@@ -0,0 +1,89 @@
/*
* Functions to manipulate path strings.
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <string.h>
#include <alloca.h>
/* Reverses a string by allocating on stack. Not super-efficient but easy. */
char *strreverse(char *str)
{
int length = strlen(str);
char *tmp = alloca(length);
strcpy(tmp, str);
for (int i = 0; i < length; i++)
str[i] = tmp[length - 1 - i];
return str;
}
/*
* Splits the string str according to the given seperator, returns the
* first component, and modifies the str so that it points at the next
* available component (or a leading separator which can be filtered
* out on a subsequent call to this function).
*/
char *splitpath(char **str, char sep)
{
char *cursor = *str;
char *end;
/* Move forward until no seperator */
while (*cursor == sep) {
*cursor = '\0';
cursor++; /* Move to first char of component */
}
end = cursor;
while (*end != sep && *end != '\0')
end++; /* Move until end of component */
if (*end == sep) { /* if ended with separator */
*end = '\0'; /* finish component by null */
if (*(end + 1) != '\0') /* if more components after, */
*str = end + 1; /* assign beginning to str */
else
*str = end; /* else str is also depleted, give null */
} else /* if end was null, that means the end for str, too. */
*str = end;
return cursor;
}
/* Same as split path, but splits components from the end. Slow. */
char *splitpath_end(char **path, char sep)
{
char *component;
/* Reverse the string */
strreverse(*path);
/* Pick one from the start */
component = splitpath(path, sep);
/* Reverse the rest back to original. */
strreverse(*path);
return component;
}
/* Splitpath test program. Tests all 3 functions.
int main()
{
char str1[256] = "/a/b/c/d/////e/f";
char *str2 = malloc(strlen(str1) + 1);
char *comp;
strcpy(str2, str1);
comp = splitpath_end(&str2, '/');
while (*comp) {
printf("%s and %s\n", comp, str2);
comp = splitpath_end(&str2, '/');
}
}
*/

View File

@@ -7,39 +7,7 @@
#include <vfs.h>
#include <stat.h>
#include <l4/api/errno.h>
/*
* Splits the string str according to the given seperator, returns the
* first component, and modifies the str so that it points at the next
* available component (or a leading separator which can be filtered
* out on a subsequent call to this function).
*/
char *splitpath(char **str, char sep)
{
char *cursor = *str;
char *end;
/* Move forward until no seperator */
while (*cursor == sep) {
*cursor = '\0';
cursor++; /* Move to first char of component */
}
end = cursor;
while (*end != sep && *end != '\0')
end++; /* Move until end of component */
if (*end == sep) { /* if ended with separator */
*end = '\0'; /* finish component by null */
if (*(end + 1) != '\0') /* if more components after, */
*str = end + 1; /* assign beginning to str */
else
*str = end; /* else str is also depleted, give null */
} else /* if end was null, that means the end for str, too. */
*str = end;
return cursor;
}
#include <lib/pathstr.h>
/*
* Given a dentry that has been populated by readdir with children dentries

View File

@@ -204,6 +204,77 @@ int memfs_write_vnode(struct superblock *sb, struct vnode *v)
return 0;
}
int memfs_vnode_mkdir(struct vnode *v, char *dirname)
{
struct dentry *d, *parent = list_entry(v->dentries.next,
struct dentry, vref);
struct memfs_dentry *memfsd;
struct dentry *newd;
struct vnode *newv;
int err;
/*
* Precautions to prove that parent is the *only* dentry,
* since directories can't have multiple dentries associated
* with them.
*/
BUG_ON(list_empty(&v->dentries));
BUG_ON(parent->vref.next != &v->dentries);
BUG_ON(!vfs_isdir(v));
/* Populate the children */
if ((err = v->ops.readdir(v)) < 0)
return err;
/* Check there's no existing child with same name */
list_for_each_entry(d, &parent->children, child) {
/* Does the name exist as a child? */
if(d->ops.compare(d, dirname))
return -EEXIST;
}
/* Allocate a new vnode for the new directory */
if (IS_ERR(newv = v->sb->ops->alloc_vnode(v->sb)))
return (int)newv;
/* Initialise the vnode */
vfs_set_type(newv, S_IFDIR);
/* Get the next directory entry available on the parent vnode */
if (v->dirbuf.npages * PAGE_SIZE <= v->size)
return -ENOSPC;
memfsd = (struct memfs_dentry *)&v->dirbuf.buffer[v->size];
memfsd->offset = v->size;
memfsd->rlength = sizeof(*memfsd);
memfsd->inum = ((struct memfs_inode *)newv->inode)->inum;
strncpy((char *)memfsd->name, dirname, MEMFS_DNAME_MAX);
memfsd->name[MEMFS_DNAME_MAX - 1] = '\0';
/* Update parent vnode */
v->size += sizeof(*memfsd);
/* Allocate a new vfs dentry */
if (!(newd = vfs_alloc_dentry()))
return -ENOMEM;
/* Initialise it */
newd->ops = generic_dentry_operations;
newd->parent = parent;
newd->vnode = newv;
/* Associate dentry with its vnode */
list_add(&newd->vref, &newd->vnode->dentries);
/* Associate dentry with its parent */
list_add(&newd->child, &parent->children);
/* Add both vnode and dentry to their flat caches */
list_add(&newd->cache_list, &dentry_cache);
list_add(&newv->cache_list, &vnode_cache);
return 0;
}
/*
* Reads the vnode directory contents into vnode's buffer in a posix-compliant
* struct dirent format.
@@ -220,9 +291,13 @@ int memfs_vnode_readdir(struct vnode *v)
struct dentry *parent = list_entry(v->dentries.next,
struct dentry, vref);
/* Check directory type */
if (!vfs_isdir(v))
return -ENOTDIR;
/*
* Precautions to prove that parent is the *only* dentry,
* since directories can't have multiple dentries associated
* with them.
*/
BUG_ON(parent->vref.next != &v->dentries);
BUG_ON(!vfs_isdir(v));
/* If a buffer is there, it means the directory is already read */
if (v->dirbuf.buffer)
@@ -279,8 +354,10 @@ int memfs_vnode_readdir(struct vnode *v)
return 0;
}
struct vnode_ops memfs_vnode_operations = {
.readdir = memfs_vnode_readdir,
.mkdir = memfs_vnode_mkdir,
};
struct superblock_ops memfs_superblock_operations = {

View File

@@ -8,6 +8,7 @@
#include <l4lib/ipcdefs.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include <lib/pathstr.h>
#include <lib/malloc.h>
#include <string.h>
#include <stdio.h>
@@ -38,19 +39,22 @@ int send_pager_opendata(l4id_t sender, int fd, unsigned long vnum)
return 0;
}
int do_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
/* FIXME:
* - Is it already open?
* - Allocate a copy of path string since lookup destroys it
* - Check flags and mode.
*/
int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
{
struct vnode *v;
struct tcb *t;
int fd;
char *copypath = kmalloc(strlen(pathname) + 1);
/* FIXME: Use strnlen */
char *pathcopy = kmalloc(strlen(pathname));
/* FIXME: Use strncpy */
memcpy(pathcopy, pathname, strlen(pathname));
strcpy(copypath, pathname);
/* Get the vnode */
if (IS_ERR(v = vfs_lookup_bypath(vfs_root.pivot->sb, pathcopy)))
if (IS_ERR(v = vfs_lookup_bypath(vfs_root.pivot->sb, copypath)))
return (int)v;
/* Get the task */
@@ -68,18 +72,32 @@ int do_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
return 0;
}
/* FIXME:
* - Is it already open?
* - Allocate a copy of path string since lookup destroys it
* - Check flags and mode.
*/
int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
{
return do_open(sender, pathname, flags, mode);
}
int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode)
{
char *parentpath, *pathbuf = kmalloc(strlen(pathname) + 1);
struct vnode *vparent;
char *newdir_name;
int err;
strcpy(pathbuf, pathname);
parentpath = pathbuf;
/* The last component is to be created */
newdir_name = splitpath_end(&parentpath, '/');
/* Check that the parentdir exists. */
if (IS_ERR(vparent = vfs_lookup_bypath(vfs_root.pivot->sb, parentpath)))
return (int)vparent;
/* The parent vnode must be a directory. */
if (!vfs_isdir(vparent))
return -ENOENT;
/* Create new directory under the parent */
if ((err = vparent->ops.mkdir(vparent, newdir_name)) < 0)
return err;
kfree(pathbuf);
return 0;
}