mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
Added sys_mkdir and memfs_vnode_mkdir() functions. Untested but all implemented.
This commit is contained in:
@@ -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);
|
||||
|
||||
9
tasks/fs0/include/lib/pathstr.h
Normal file
9
tasks/fs0/include/lib/pathstr.h
Normal 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__ */
|
||||
89
tasks/fs0/src/lib/pathstr.c
Normal file
89
tasks/fs0/src/lib/pathstr.c
Normal 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, '/');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user