2002-07-09 16:24:59 +04:00
|
|
|
/* Virtual File System */
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
|
|
|
** Distributed under the terms of the NewOS License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <kernel.h>
|
|
|
|
#include <stage2.h>
|
|
|
|
#include <vfs.h>
|
|
|
|
#include <vm.h>
|
|
|
|
#include <vm_cache.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <khash.h>
|
|
|
|
#include <lock.h>
|
|
|
|
#include <thread.h>
|
|
|
|
#include <memheap.h>
|
|
|
|
#include <arch/cpu.h>
|
|
|
|
#include <elf.h>
|
|
|
|
#include <rootfs.h>
|
|
|
|
#include <bootfs.h>
|
|
|
|
#include <devfs.h>
|
|
|
|
#include <Errors.h>
|
2002-07-12 02:21:56 +04:00
|
|
|
#include <kerrors.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <atomic.h>
|
|
|
|
#include <fd.h>
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
#include <OS.h>
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <rootfs.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <resource.h>
|
|
|
|
#include <sys/stat.h>
|
2002-07-14 09:13:20 +04:00
|
|
|
#include <fcntl.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
#ifndef MAKE_NOIZE
|
|
|
|
# define MAKE_NOIZE 0
|
|
|
|
#endif
|
|
|
|
#if MAKE_NOIZE
|
|
|
|
# define PRINT(x) dprintf x
|
|
|
|
# define FUNCTION(x) dprintf x
|
|
|
|
#else
|
|
|
|
# define PRINT(x) ;
|
|
|
|
# define FUNCTION(x) ;
|
|
|
|
#endif
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// ToDo: remove this and include StorageDefs.h once it's there...
|
|
|
|
#ifndef B_FILE_NAME_LENGTH
|
|
|
|
# define B_FILE_NAME_LENGTH 256
|
|
|
|
#endif
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
struct vnode {
|
|
|
|
struct vnode *next;
|
|
|
|
struct vnode *mount_prev;
|
|
|
|
struct vnode *mount_next;
|
|
|
|
struct vm_cache *cache;
|
|
|
|
fs_id fsid;
|
|
|
|
vnode_id vnid;
|
|
|
|
fs_vnode priv_vnode;
|
|
|
|
struct fs_mount *mount;
|
|
|
|
struct vnode *covered_by;
|
|
|
|
int ref_count;
|
|
|
|
bool delete_me;
|
|
|
|
bool busy;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct vnode_hash_key {
|
|
|
|
fs_id fsid;
|
|
|
|
vnode_id vnid;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct fs_container {
|
|
|
|
struct fs_container *next;
|
|
|
|
struct fs_calls *calls;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
#define FS_CALL(vnode,call) (vnode->mount->fs->calls->call)
|
|
|
|
static struct fs_container *fs_list;
|
|
|
|
|
|
|
|
struct fs_mount {
|
|
|
|
struct fs_mount *next;
|
|
|
|
struct fs_container *fs;
|
|
|
|
fs_id id;
|
|
|
|
void *cookie;
|
|
|
|
char *mount_point;
|
|
|
|
recursive_lock rlock;
|
|
|
|
struct vnode *root_vnode;
|
|
|
|
struct vnode *covers_vnode;
|
|
|
|
struct vnode *vnodes_head;
|
|
|
|
struct vnode *vnodes_tail;
|
|
|
|
bool unmounting;
|
|
|
|
};
|
|
|
|
|
|
|
|
static mutex vfs_mutex;
|
|
|
|
static mutex vfs_mount_mutex;
|
|
|
|
static mutex vfs_mount_op_mutex;
|
|
|
|
static mutex vfs_vnode_mutex;
|
|
|
|
|
|
|
|
/* function declarations */
|
|
|
|
static int vfs_mount(char *path, const char *device, const char *fs_name, void *args, bool kernel);
|
|
|
|
static int vfs_unmount(char *path, bool kernel);
|
|
|
|
|
|
|
|
static ssize_t vfs_read(struct file_descriptor *, void *, off_t, size_t *);
|
|
|
|
static ssize_t vfs_write(struct file_descriptor *, const void *, off_t, size_t *);
|
|
|
|
static int vfs_ioctl(struct file_descriptor *, ulong, void *buf, size_t len);
|
|
|
|
static status_t vfs_read_dir(struct file_descriptor *,struct dirent *buffer,size_t bufferSize,uint32 *_count);
|
|
|
|
static status_t vfs_rewind_dir(struct file_descriptor *);
|
2002-07-14 09:13:20 +04:00
|
|
|
static int vfs_read_stat(struct file_descriptor *, struct stat *);
|
2002-07-09 16:24:59 +04:00
|
|
|
static int vfs_close(struct file_descriptor *, int, struct io_context *);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
static int common_ioctl(struct file_descriptor *, ulong, void *buf, size_t len);
|
|
|
|
static int common_read_stat(struct file_descriptor *, struct stat *);
|
|
|
|
|
|
|
|
static ssize_t file_read(struct file_descriptor *, void *, off_t, size_t *);
|
|
|
|
static ssize_t file_write(struct file_descriptor *, const void *, off_t, size_t *);
|
2002-07-17 11:55:51 +04:00
|
|
|
static off_t file_seek(struct file_descriptor *, off_t pos, int seek_type);
|
2002-07-14 09:13:20 +04:00
|
|
|
static status_t dir_read(struct file_descriptor *,struct dirent *buffer,size_t bufferSize,uint32 *_count);
|
|
|
|
static status_t dir_rewind(struct file_descriptor *);
|
|
|
|
static void file_free_fd(struct file_descriptor *);
|
2002-07-17 11:55:51 +04:00
|
|
|
static int file_close(struct file_descriptor *);
|
2002-07-14 09:13:20 +04:00
|
|
|
static void dir_free_fd(struct file_descriptor *);
|
2002-07-17 11:55:51 +04:00
|
|
|
static int dir_close(struct file_descriptor *);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
static int vfs_open(char *path, int omode, bool kernel);
|
|
|
|
static int vfs_open_dir(char *path, bool kernel);
|
|
|
|
static int vfs_create(char *path, int omode, int perms, bool kernel);
|
|
|
|
static int vfs_create_dir(char *path, int perms, bool kernel);
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
static status_t dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize);
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
struct fd_ops file_ops = {
|
|
|
|
"file",
|
|
|
|
file_read,
|
|
|
|
file_write,
|
|
|
|
file_seek,
|
|
|
|
common_ioctl,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
common_read_stat,
|
2002-07-17 11:55:51 +04:00
|
|
|
file_close,
|
2002-07-14 09:13:20 +04:00
|
|
|
file_free_fd
|
|
|
|
};
|
|
|
|
|
|
|
|
struct fd_ops dir_ops = {
|
|
|
|
"directory",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
common_ioctl,
|
|
|
|
dir_read,
|
|
|
|
dir_rewind,
|
|
|
|
common_read_stat,
|
2002-07-17 11:55:51 +04:00
|
|
|
dir_close,
|
2002-07-14 09:13:20 +04:00
|
|
|
dir_free_fd
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#define VNODE_HASH_TABLE_SIZE 1024
|
|
|
|
static void *vnode_table;
|
|
|
|
static struct vnode *root_vnode;
|
|
|
|
static vnode_id next_vnode_id = 0;
|
|
|
|
|
|
|
|
#define MOUNTS_HASH_TABLE_SIZE 16
|
|
|
|
static void *mounts_table;
|
|
|
|
static fs_id next_fsid = 0;
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
mount_compare(void *_m, const void *_key)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount = _m;
|
|
|
|
const fs_id *id = _key;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount->id == *id)
|
2002-07-09 16:24:59 +04:00
|
|
|
return 0;
|
2002-07-17 11:55:51 +04:00
|
|
|
|
|
|
|
return -1;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
mount_hash(void *_m, const void *_key, unsigned int range)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount = _m;
|
|
|
|
const fs_id *id = _key;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount)
|
2002-07-09 16:24:59 +04:00
|
|
|
return mount->id % range;
|
2002-07-17 11:55:51 +04:00
|
|
|
|
|
|
|
return *id % range;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct fs_mount *
|
|
|
|
fsid_to_mount(fs_id id)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
|
|
|
|
mutex_lock(&vfs_mount_mutex);
|
|
|
|
|
|
|
|
mount = hash_lookup(mounts_table, &id);
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_mount_mutex);
|
|
|
|
|
|
|
|
return mount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vnode_compare(void *_v, const void *_key)
|
|
|
|
{
|
|
|
|
struct vnode *v = _v;
|
|
|
|
const struct vnode_hash_key *key = _key;
|
|
|
|
|
|
|
|
if(v->fsid == key->fsid && v->vnid == key->vnid)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
vnode_hash(void *_v, const void *_key, unsigned int range)
|
|
|
|
{
|
|
|
|
struct vnode *v = _v;
|
|
|
|
const struct vnode_hash_key *key = _key;
|
|
|
|
|
|
|
|
#define VHASH(fsid, vnid) (((uint32)((vnid)>>32) + (uint32)(vnid)) ^ (uint32)(fsid))
|
|
|
|
|
|
|
|
if (v != NULL)
|
|
|
|
return (VHASH(v->fsid, v->vnid) % range);
|
|
|
|
else
|
|
|
|
return (VHASH(key->fsid, key->vnid) % range);
|
|
|
|
|
|
|
|
#undef VHASH
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
static int init_vnode(struct vnode *v)
|
|
|
|
{
|
|
|
|
v->next = NULL;
|
|
|
|
v->mount_prev = NULL;
|
|
|
|
v->mount_next = NULL;
|
|
|
|
v->priv_vnode = NULL;
|
|
|
|
v->cache = NULL;
|
|
|
|
v->ref_count = 0;
|
|
|
|
v->vnid = 0;
|
|
|
|
v->fsid = 0;
|
|
|
|
v->delete_me = false;
|
|
|
|
v->busy = false;
|
|
|
|
v->covered_by = NULL;
|
|
|
|
v->mount = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_vnode_to_mount_list(struct vnode *v, struct fs_mount *mount)
|
|
|
|
{
|
|
|
|
recursive_lock_lock(&mount->rlock);
|
|
|
|
|
|
|
|
v->mount_next = mount->vnodes_head;
|
|
|
|
v->mount_prev = NULL;
|
|
|
|
mount->vnodes_head = v;
|
|
|
|
if(!mount->vnodes_tail)
|
|
|
|
mount->vnodes_tail = v;
|
|
|
|
|
|
|
|
recursive_lock_unlock(&mount->rlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_vnode_from_mount_list(struct vnode *v, struct fs_mount *mount)
|
|
|
|
{
|
|
|
|
recursive_lock_lock(&mount->rlock);
|
|
|
|
|
|
|
|
if(v->mount_next)
|
|
|
|
v->mount_next->mount_prev = v->mount_prev;
|
|
|
|
else
|
|
|
|
mount->vnodes_tail = v->mount_prev;
|
|
|
|
if(v->mount_prev)
|
|
|
|
v->mount_prev->mount_next = v->mount_next;
|
|
|
|
else
|
|
|
|
mount->vnodes_head = v->mount_next;
|
|
|
|
|
|
|
|
v->mount_prev = v->mount_next = NULL;
|
|
|
|
|
|
|
|
recursive_lock_unlock(&mount->rlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct vnode *
|
|
|
|
create_new_vnode(void)
|
|
|
|
{
|
|
|
|
struct vnode *v;
|
|
|
|
|
|
|
|
v = (struct vnode *)kmalloc(sizeof(struct vnode));
|
|
|
|
if (v == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memset(v, 0, sizeof(struct vnode));//max_commit - old_store_commitment + commitment(v);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
dec_vnode_ref_count(struct vnode *v, bool free_mem, bool r)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
int old_ref;
|
|
|
|
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
if (v->busy == true)
|
|
|
|
panic("dec_vnode_ref_count called on vnode that was busy! vnode %p\n", v);
|
|
|
|
|
|
|
|
old_ref = atomic_add(&v->ref_count, -1);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("dec_vnode_ref_count: vnode 0x%p, ref now %d\n", v, v->ref_count));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
if (old_ref == 1) {
|
|
|
|
v->busy = true;
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
/* if we have a vm_cache attached, remove it */
|
|
|
|
if (v->cache)
|
|
|
|
vm_cache_release_ref((vm_cache_ref *)v->cache);
|
|
|
|
v->cache = NULL;
|
|
|
|
|
|
|
|
if (v->delete_me)
|
2002-07-14 09:13:20 +04:00
|
|
|
FS_CALL(v,fs_remove_vnode)(v->mount->cookie, v->priv_vnode, r);
|
2002-07-09 16:24:59 +04:00
|
|
|
else
|
2002-07-14 09:13:20 +04:00
|
|
|
FS_CALL(v,fs_put_vnode)(v->mount->cookie, v->priv_vnode, r);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
remove_vnode_from_mount_list(v, v->mount);
|
|
|
|
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
hash_remove(vnode_table, v);
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
if (free_mem)
|
|
|
|
kfree(v);
|
|
|
|
err = 1;
|
|
|
|
} else {
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
err = 0;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
inc_vnode_ref_count(struct vnode *v)
|
|
|
|
{
|
|
|
|
atomic_add(&v->ref_count, 1);
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("inc_vnode_ref_count: vnode 0x%p, ref now %d\n", v, v->ref_count));
|
2002-07-09 16:24:59 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct vnode *
|
|
|
|
lookup_vnode(fs_id fsid, vnode_id vnid)
|
|
|
|
{
|
|
|
|
struct vnode_hash_key key;
|
|
|
|
|
|
|
|
key.fsid = fsid;
|
|
|
|
key.vnid = vnid;
|
|
|
|
|
|
|
|
return hash_lookup(vnode_table, &key);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-19 01:06:02 +04:00
|
|
|
get_vnode(fs_id fsid, vnode_id vnid, struct vnode **outv, int reenter)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct vnode *v;
|
|
|
|
int err;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("get_vnode: fsid %d vnid 0x%Lx 0x%p\n", fsid, vnid,outv));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
do {
|
|
|
|
v = lookup_vnode(fsid, vnid);
|
|
|
|
if (v) {
|
|
|
|
if (v->busy) {
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
thread_snooze(10000); // 10 ms
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while(0);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("get_vnode: tried to lookup vnode, got 0x%p\n", v));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
if (v) {
|
|
|
|
inc_vnode_ref_count(v);
|
|
|
|
} else {
|
|
|
|
// we need to create a new vnode and read it in
|
|
|
|
v = create_new_vnode();
|
2002-07-14 09:13:20 +04:00
|
|
|
if (!v) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ENOMEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
v->fsid = fsid;
|
|
|
|
v->vnid = vnid;
|
|
|
|
v->mount = fsid_to_mount(fsid);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (!v->mount) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ERR_INVALID_HANDLE;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
v->busy = true;
|
|
|
|
hash_insert(vnode_table, v);
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
add_vnode_to_mount_list(v, v->mount);
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
err = FS_CALL(v,fs_get_vnode)(v->mount->cookie, vnid, &v->priv_vnode, reenter);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
remove_vnode_from_mount_list(v, v->mount);
|
|
|
|
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err1;
|
|
|
|
|
|
|
|
v->busy = false;
|
|
|
|
v->ref_count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("get_vnode: returning 0x%p\n", v));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
*outv = v;
|
|
|
|
return B_NO_ERROR;
|
|
|
|
|
|
|
|
err1:
|
|
|
|
hash_remove(vnode_table, v);
|
|
|
|
err:
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (v)
|
2002-07-09 16:24:59 +04:00
|
|
|
kfree(v);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
put_vnode(struct vnode *v)
|
|
|
|
{
|
|
|
|
dec_vnode_ref_count(v, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_get_vnode(fs_id fsid, vnode_id vnid, fs_vnode *fsv)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct vnode *v;
|
|
|
|
|
|
|
|
err = get_vnode(fsid, vnid, &v, true);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
*fsv = v->priv_vnode;
|
|
|
|
return B_NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_put_vnode(fs_id fsid, vnode_id vnid)
|
|
|
|
{
|
|
|
|
struct vnode *v;
|
|
|
|
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
v = lookup_vnode(fsid, vnid);
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
if (v)
|
|
|
|
dec_vnode_ref_count(v, true, true);
|
|
|
|
|
|
|
|
return B_NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
vfs_vnode_acquire_ref(void *v)
|
|
|
|
{
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_vnode_acquire_ref: vnode 0x%p\n", v));
|
2002-07-09 16:24:59 +04:00
|
|
|
inc_vnode_ref_count((struct vnode *)v);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
vfs_vnode_release_ref(void *v)
|
|
|
|
{
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_vnode_release_ref: vnode 0x%p\n", v));
|
2002-07-09 16:24:59 +04:00
|
|
|
dec_vnode_ref_count((struct vnode *)v, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_remove_vnode(fs_id fsid, vnode_id vnid)
|
|
|
|
{
|
|
|
|
struct vnode *v;
|
|
|
|
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
v = lookup_vnode(fsid, vnid);
|
|
|
|
if(v)
|
|
|
|
v->delete_me = true;
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
vfs_get_cache_ptr(void *vnode)
|
|
|
|
{
|
|
|
|
return ((struct vnode *)vnode)->cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_set_cache_ptr(void *vnode, void *cache)
|
|
|
|
{
|
|
|
|
if(test_and_set((int *)&(((struct vnode *)vnode)->cache), (int)cache, 0) == 0)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2002-07-14 09:13:20 +04:00
|
|
|
file_free_fd(struct file_descriptor *descriptor)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = descriptor->vnode;
|
|
|
|
|
|
|
|
if (vnode != NULL) {
|
2002-07-17 11:55:51 +04:00
|
|
|
//FS_CALL(vnode,fs_close)(vnode->mount->cookie, vnode->priv_vnode, descriptor->cookie);
|
2002-07-14 09:13:20 +04:00
|
|
|
FS_CALL(vnode,fs_free_cookie)(vnode->mount->cookie, vnode->priv_vnode, descriptor->cookie);
|
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
dir_free_fd(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->vnode;
|
|
|
|
|
|
|
|
if (vnode != NULL) {
|
2002-07-17 11:55:51 +04:00
|
|
|
//FS_CALL(vnode,fs_close_dir)(vnode->mount->cookie, vnode->priv_vnode, descriptor->cookie);
|
2002-07-14 09:13:20 +04:00
|
|
|
FS_CALL(vnode,fs_free_dir_cookie)(vnode->mount->cookie, vnode->priv_vnode, descriptor->cookie);
|
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct vnode *
|
|
|
|
get_vnode_from_fd(struct io_context *ioctx, int fd)
|
|
|
|
{
|
|
|
|
struct file_descriptor *f;
|
|
|
|
struct vnode *v;
|
|
|
|
|
|
|
|
f = get_fd(ioctx, fd);
|
|
|
|
if (!f)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
v = f->vnode;
|
|
|
|
if (!v)
|
|
|
|
goto out;
|
|
|
|
inc_vnode_ref_count(v);
|
|
|
|
|
|
|
|
out:
|
|
|
|
put_fd(f);
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct fs_container *
|
|
|
|
find_fs(const char *fs_name)
|
|
|
|
{
|
|
|
|
struct fs_container *fs = fs_list;
|
|
|
|
while(fs != NULL) {
|
|
|
|
if(strcmp(fs_name, fs->name) == 0) {
|
|
|
|
return fs;
|
|
|
|
}
|
|
|
|
fs = fs->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
path_to_vnode(char *path, struct vnode **v, bool kernel)
|
|
|
|
{
|
|
|
|
char *p = path;
|
|
|
|
char *next_p;
|
|
|
|
struct vnode *curr_v;
|
|
|
|
struct vnode *next_v;
|
|
|
|
vnode_id vnid;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
// figure out if we need to start at root or at cwd
|
|
|
|
if (*p == '/') {
|
|
|
|
while (*++p == '/')
|
|
|
|
;
|
|
|
|
curr_v = root_vnode;
|
|
|
|
inc_vnode_ref_count(curr_v);
|
|
|
|
} else {
|
|
|
|
struct io_context *ioctx = get_current_io_context(kernel);
|
|
|
|
mutex_lock(&ioctx->io_mutex);
|
|
|
|
curr_v = ioctx->cwd;
|
|
|
|
inc_vnode_ref_count(curr_v);
|
|
|
|
mutex_unlock(&ioctx->io_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
// dprintf("path_to_vnode: top of loop. p 0x%x, *p = %c, p = '%s'\n", p, *p, p);
|
|
|
|
|
|
|
|
// done?
|
2002-07-14 09:13:20 +04:00
|
|
|
if (*p == '\0') {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// walk to find the next component
|
|
|
|
for (next_p = p+1; *next_p != '\0' && *next_p != '/'; next_p++);
|
|
|
|
|
|
|
|
if (*next_p == '/') {
|
|
|
|
*next_p = '\0';
|
|
|
|
do
|
|
|
|
next_p++;
|
|
|
|
while (*next_p == '/');
|
|
|
|
}
|
|
|
|
|
|
|
|
// see if the .. is at the root of a mount
|
|
|
|
if (strcmp("..", p) == 0 && curr_v->mount->root_vnode == curr_v) {
|
|
|
|
// move to the covered vnode so we pass the '..' parse to the underlying filesystem
|
|
|
|
if (curr_v->mount->covers_vnode) {
|
|
|
|
next_v = curr_v->mount->covers_vnode;
|
|
|
|
inc_vnode_ref_count(next_v);
|
|
|
|
dec_vnode_ref_count(curr_v, true, false);
|
|
|
|
curr_v = next_v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// tell the filesystem to parse this path
|
|
|
|
err = curr_v->mount->fs->calls->fs_lookup(curr_v->mount->cookie, curr_v->priv_vnode, p, &vnid);
|
|
|
|
if (err < 0) {
|
|
|
|
dec_vnode_ref_count(curr_v, true, false);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
|
|
|
|
// from inside the filesystem, thus the vnode would have to be in the list and it's
|
|
|
|
// ref count incremented at this point
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
next_v = lookup_vnode(curr_v->fsid, vnid);
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
if (!next_v) {
|
|
|
|
// pretty screwed up here
|
|
|
|
panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", curr_v->fsid, vnid);
|
|
|
|
err = ERR_VFS_PATH_NOT_FOUND;
|
|
|
|
dec_vnode_ref_count(curr_v, true, false);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// decrease the ref count on the old dir we just looked up into
|
|
|
|
dec_vnode_ref_count(curr_v, true, false);
|
|
|
|
|
|
|
|
p = next_p;
|
|
|
|
curr_v = next_v;
|
|
|
|
|
|
|
|
// see if we hit a mount point
|
|
|
|
if (curr_v->covered_by) {
|
|
|
|
next_v = curr_v->covered_by;
|
|
|
|
inc_vnode_ref_count(next_v);
|
|
|
|
dec_vnode_ref_count(curr_v, true, false);
|
|
|
|
curr_v = next_v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*v = curr_v;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns the vnode in the next to last segment of the path, and returns
|
|
|
|
* the last portion in filename.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
path_to_dir_vnode(char *path, struct vnode **v, char *filename, bool kernel)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
p = strrchr(path, '/');
|
|
|
|
if (!p) {
|
|
|
|
// this path is single segment with no '/' in it
|
|
|
|
// ex. "foo"
|
|
|
|
strcpy(filename, path);
|
|
|
|
strcpy(path, ".");
|
|
|
|
} else {
|
|
|
|
// replace the filename portion of the path with a '.'
|
|
|
|
strcpy(filename, p+1);
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (p[1] != '\0'){
|
2002-07-09 16:24:59 +04:00
|
|
|
p[1] = '.';
|
|
|
|
p[2] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return path_to_vnode(path, v, kernel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
/** Gets the full path to a given directory vnode.
|
|
|
|
* It uses the fs_get_vnode_name() call to get the name of a vnode; if a
|
|
|
|
* file system doesn't support this call, it will fall back to iterating
|
|
|
|
* through the parent directory to get the name of the child.
|
|
|
|
*
|
|
|
|
* To detect circular loops, it supports a maximum tree depth
|
|
|
|
* of 256 levels.
|
|
|
|
*
|
|
|
|
* Note that the path may not be correct the time this function returns!
|
|
|
|
* It doesn't use any locking to prevent returning the correct path, as
|
|
|
|
* paths aren't safe anyway: the path to a file can change at any time.
|
|
|
|
*/
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
status_t
|
|
|
|
dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
|
|
|
{
|
|
|
|
/* this implementation is currently bound to SYS_MAX_PATH_LEN */
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int32 insert = sizeof(path);
|
|
|
|
int32 maxLevel = 256;
|
|
|
|
int32 length;
|
|
|
|
status_t status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
if (vnode == NULL || buffer == NULL)
|
|
|
|
return EINVAL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 08:20:07 +04:00
|
|
|
// we don't use get_vnode() here because this call is more
|
|
|
|
// efficient and does all we need from get_vnode()
|
2002-07-19 01:06:02 +04:00
|
|
|
inc_vnode_ref_count(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
path[--insert] = '\0';
|
|
|
|
|
|
|
|
while (true) {
|
2002-07-19 08:20:07 +04:00
|
|
|
// the name buffer is also used for fs_read_dir()
|
|
|
|
char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
|
|
|
char *name = &((struct dirent *)nameBuffer)->d_name[0];
|
|
|
|
vnode_id parentId, id;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// lookup the parent vnode
|
|
|
|
status = FS_CALL(vnode,fs_lookup)(vnode->mount->cookie,vnode->priv_vnode,"..",&parentId);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 08:20:07 +04:00
|
|
|
// Does the file system support getting the name of a vnode?
|
|
|
|
// If so, get it here...
|
|
|
|
if (status == B_OK && FS_CALL(vnode,fs_get_vnode_name))
|
|
|
|
status = FS_CALL(vnode,fs_get_vnode_name)(vnode->mount->cookie,vnode->priv_vnode,name,B_FILE_NAME_LENGTH);
|
|
|
|
|
|
|
|
// ... if not, find it out later (by iterating through
|
|
|
|
// the parent directory, searching for the id)
|
|
|
|
id = vnode->vnid;
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// release the current vnode, we only need its parent from now on
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
// don't go deeper as 'maxLevel' to prevent circular loops
|
|
|
|
if (maxLevel-- < 0)
|
|
|
|
return ELOOP;
|
|
|
|
|
|
|
|
if (parentId == vnode->vnid) {
|
|
|
|
// we have reached the root level directory of this file system
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the parent vnode. The parent of the vnode may have already
|
|
|
|
// changed, though, which would result in an incorrect path
|
|
|
|
status = get_vnode(vnode->mount->id,parentId,&vnode,0);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-07-19 08:20:07 +04:00
|
|
|
if (!FS_CALL(vnode,fs_get_vnode_name)) {
|
|
|
|
// If we don't got the vnode's name yet, we have to search for it
|
|
|
|
// in the parent directory now
|
2002-07-19 01:06:02 +04:00
|
|
|
file_cookie cookie;
|
|
|
|
|
|
|
|
status = FS_CALL(vnode,fs_open_dir)(vnode->mount->cookie,vnode->priv_vnode,&cookie);
|
|
|
|
if (status >= B_OK) {
|
2002-07-19 08:20:07 +04:00
|
|
|
struct dirent *dirent = (struct dirent *)nameBuffer;
|
|
|
|
while (true) {
|
|
|
|
uint32 num = 1;
|
|
|
|
status = FS_CALL(vnode,fs_read_dir)(vnode->mount->cookie,vnode->priv_vnode,cookie,dirent,sizeof(nameBuffer),&num);
|
|
|
|
if (status < B_OK)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (id == dirent->d_ino)
|
|
|
|
// found correct entry!
|
|
|
|
break;
|
|
|
|
}
|
2002-07-19 01:06:02 +04:00
|
|
|
FS_CALL(vnode,fs_close_dir)(vnode->mount->cookie,vnode->priv_vnode,cookie);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-19 01:06:02 +04:00
|
|
|
|
2002-07-19 08:20:07 +04:00
|
|
|
if (status < B_OK) {
|
|
|
|
put_vnode(vnode);
|
|
|
|
return status;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-19 01:06:02 +04:00
|
|
|
|
|
|
|
// add the name infront of the current path
|
|
|
|
name[B_FILE_NAME_LENGTH - 1] = '\0';
|
|
|
|
length = strlen(name);
|
|
|
|
insert -= length;
|
|
|
|
if (insert <= 0) {
|
|
|
|
put_vnode(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
return ENOBUFS;
|
2002-07-19 01:06:02 +04:00
|
|
|
}
|
|
|
|
memcpy(path + insert, name, length);
|
2002-07-19 08:20:07 +04:00
|
|
|
path[--insert] = '/';
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// add the mountpoint
|
|
|
|
length = strlen(vnode->mount->mount_point);
|
|
|
|
if (bufferSize - (sizeof(path) - insert) < length + 1)
|
|
|
|
return ENOBUFS;
|
|
|
|
|
|
|
|
memcpy(buffer, vnode->mount->mount_point, length);
|
2002-07-19 08:20:07 +04:00
|
|
|
if (insert != sizeof(path))
|
|
|
|
memcpy(buffer + length, path + insert, sizeof(path) - insert);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
/** Sets up a new io_control structure, and inherits the properties
|
|
|
|
* of the parent io_control if it is given.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void *
|
|
|
|
vfs_new_io_context(void *_parent_ioctx)
|
|
|
|
{
|
|
|
|
size_t table_size;
|
|
|
|
struct io_context *ioctx;
|
|
|
|
struct io_context *parent_ioctx;
|
|
|
|
|
|
|
|
ioctx = kmalloc(sizeof(struct io_context));
|
|
|
|
if (ioctx == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memset(ioctx, 0, sizeof(struct io_context));
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
parent_ioctx = (struct io_context *)_parent_ioctx;
|
|
|
|
if (parent_ioctx)
|
|
|
|
table_size = parent_ioctx->table_size;
|
|
|
|
else
|
|
|
|
table_size = DEFAULT_FD_TABLE_SIZE;
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
ioctx->fds = kmalloc(sizeof(struct file_descriptor *) * table_size);
|
|
|
|
if (ioctx->fds == NULL) {
|
|
|
|
kfree(ioctx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(ioctx->fds, 0, sizeof(struct file_descriptor *) * table_size);
|
|
|
|
|
|
|
|
if (mutex_init(&ioctx->io_mutex, "ioctx_mutex") < 0) {
|
|
|
|
kfree(ioctx->fds);
|
|
|
|
kfree(ioctx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* copy parent files
|
|
|
|
*/
|
|
|
|
if (parent_ioctx) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
mutex_lock(&parent_ioctx->io_mutex);
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
ioctx->cwd = parent_ioctx->cwd;
|
|
|
|
if (ioctx->cwd)
|
2002-07-09 16:24:59 +04:00
|
|
|
inc_vnode_ref_count(ioctx->cwd);
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
for (i = 0; i < table_size; i++) {
|
2002-07-09 16:24:59 +04:00
|
|
|
if (parent_ioctx->fds[i]) {
|
2002-07-14 09:13:20 +04:00
|
|
|
ioctx->fds[i] = parent_ioctx->fds[i];
|
2002-07-09 16:24:59 +04:00
|
|
|
atomic_add(&ioctx->fds[i]->ref_count, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&parent_ioctx->io_mutex);
|
|
|
|
} else {
|
|
|
|
ioctx->cwd = root_vnode;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (ioctx->cwd)
|
2002-07-09 16:24:59 +04:00
|
|
|
inc_vnode_ref_count(ioctx->cwd);
|
|
|
|
}
|
|
|
|
|
|
|
|
ioctx->table_size = table_size;
|
|
|
|
|
|
|
|
return ioctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_free_io_context(void *_ioctx)
|
|
|
|
{
|
|
|
|
struct io_context *ioctx = (struct io_context *)_ioctx;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (ioctx->cwd)
|
|
|
|
dec_vnode_ref_count(ioctx->cwd, true, false);
|
|
|
|
|
|
|
|
mutex_lock(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
for (i = 0; i < ioctx->table_size; i++) {
|
|
|
|
if (ioctx->fds[i])
|
|
|
|
put_fd(ioctx->fds[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
mutex_destroy(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
kfree(ioctx->fds);
|
|
|
|
kfree(ioctx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_mount(char *path, const char *device, const char *fs_name, void *args, bool kernel)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
int err = 0;
|
|
|
|
struct vnode *covered_vnode = NULL;
|
|
|
|
vnode_id root_id;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_mount: entry. path = '%s', fs_name = '%s'\n", path, fs_name));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
mutex_lock(&vfs_mount_op_mutex);
|
|
|
|
|
|
|
|
mount = (struct fs_mount *)kmalloc(sizeof(struct fs_mount));
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount == NULL) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ENOMEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
mount->mount_point = kstrdup(path);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount->mount_point == NULL) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ENOMEM;
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mount->fs = find_fs(fs_name);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount->fs == NULL) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ERR_VFS_INVALID_FS;
|
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
|
|
|
recursive_lock_create(&mount->rlock);
|
|
|
|
mount->id = next_fsid++;
|
|
|
|
mount->unmounting = false;
|
|
|
|
|
|
|
|
if(!root_vnode) {
|
|
|
|
// we haven't mounted anything yet
|
2002-07-17 11:55:51 +04:00
|
|
|
if (strcmp(path, "/") != 0) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ERR_VFS_GENERAL;
|
|
|
|
goto err3;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = mount->fs->calls->fs_mount(&mount->cookie, mount->id, device, NULL, &root_id);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err < 0) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ERR_VFS_GENERAL;
|
|
|
|
goto err3;
|
|
|
|
}
|
|
|
|
|
|
|
|
mount->covers_vnode = NULL; // this is the root mount
|
|
|
|
} else {
|
|
|
|
err = path_to_vnode(path,&covered_vnode,kernel);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err2;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (!covered_vnode) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ERR_VFS_GENERAL;
|
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX insert check to make sure covered_vnode is a DIR, or maybe it's okay for it not to be
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if ((covered_vnode != root_vnode) && (covered_vnode->mount->root_vnode == covered_vnode)){
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ERR_VFS_ALREADY_MOUNTPOINT;
|
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
|
|
|
mount->covers_vnode = covered_vnode;
|
|
|
|
|
|
|
|
// mount it
|
|
|
|
err = mount->fs->calls->fs_mount(&mount->cookie, mount->id, device, NULL, &root_id);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err4;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&vfs_mount_mutex);
|
|
|
|
|
|
|
|
// insert mount struct into list
|
|
|
|
hash_insert(mounts_table, mount);
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_mount_mutex);
|
|
|
|
|
|
|
|
err = get_vnode(mount->id, root_id, &mount->root_vnode, 0);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err5;
|
|
|
|
|
|
|
|
// XXX may be a race here
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount->covers_vnode)
|
2002-07-09 16:24:59 +04:00
|
|
|
mount->covers_vnode->covered_by = mount->root_vnode;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (!root_vnode)
|
2002-07-09 16:24:59 +04:00
|
|
|
root_vnode = mount->root_vnode;
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_mount_op_mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err5:
|
|
|
|
mount->fs->calls->fs_unmount(mount->cookie);
|
|
|
|
err4:
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount->covers_vnode)
|
2002-07-09 16:24:59 +04:00
|
|
|
dec_vnode_ref_count(mount->covers_vnode, true, false);
|
|
|
|
err3:
|
|
|
|
recursive_lock_destroy(&mount->rlock);
|
|
|
|
err2:
|
|
|
|
kfree(mount->mount_point);
|
|
|
|
err1:
|
|
|
|
kfree(mount);
|
|
|
|
err:
|
|
|
|
mutex_unlock(&vfs_mount_op_mutex);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_unmount(char *path, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *v;
|
|
|
|
struct fs_mount *mount;
|
|
|
|
int err;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
err = path_to_vnode(path, &v, kernel);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err < 0) {
|
2002-07-09 16:24:59 +04:00
|
|
|
err = ERR_VFS_PATH_NOT_FOUND;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&vfs_mount_op_mutex);
|
|
|
|
|
|
|
|
mount = fsid_to_mount(v->fsid);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (!mount)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("vfs_unmount: fsid_to_mount failed on root vnode @%p of mount\n", v);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount->root_vnode != v) {
|
2002-07-09 16:24:59 +04:00
|
|
|
// not mountpoint
|
|
|
|
dec_vnode_ref_count(v, true, false);
|
|
|
|
err = ERR_VFS_NOT_MOUNTPOINT;
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* grab the vnode master mutex to keep someone from creating a vnode
|
|
|
|
while we're figuring out if we can continue */
|
|
|
|
mutex_lock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
/* simulate the root vnode having it's refcount decremented */
|
|
|
|
mount->root_vnode->ref_count -= 2;
|
|
|
|
|
|
|
|
/* cycle through the list of vnodes associated with this mount and
|
|
|
|
make sure all of them are not busy or have refs on them */
|
|
|
|
err = 0;
|
|
|
|
for(v = mount->vnodes_head; v; v = v->mount_next) {
|
|
|
|
if(v->busy || v->ref_count != 0) {
|
|
|
|
mount->root_vnode->ref_count += 2;
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
dec_vnode_ref_count(mount->root_vnode, true, false);
|
|
|
|
err = EBUSY;
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we can safely continue, mark all of the vnodes busy and this mount
|
|
|
|
structure in unmounting state */
|
|
|
|
for(v = mount->vnodes_head; v; v = v->mount_next)
|
|
|
|
if(v != mount->root_vnode)
|
|
|
|
v->busy = true;
|
|
|
|
mount->unmounting = true;
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_vnode_mutex);
|
|
|
|
|
|
|
|
mount->covers_vnode->covered_by = NULL;
|
|
|
|
dec_vnode_ref_count(mount->covers_vnode, true, false);
|
|
|
|
|
|
|
|
/* release the ref on the root vnode twice */
|
|
|
|
dec_vnode_ref_count(mount->root_vnode, true, false);
|
|
|
|
dec_vnode_ref_count(mount->root_vnode, true, false);
|
|
|
|
|
|
|
|
// XXX when full vnode cache in place, will need to force
|
|
|
|
// a putvnode/removevnode here
|
|
|
|
|
|
|
|
/* remove the mount structure from the hash table */
|
|
|
|
mutex_lock(&vfs_mount_mutex);
|
|
|
|
hash_remove(mounts_table, mount);
|
|
|
|
mutex_unlock(&vfs_mount_mutex);
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_mount_op_mutex);
|
|
|
|
|
|
|
|
mount->fs->calls->fs_unmount(mount->cookie);
|
|
|
|
|
|
|
|
kfree(mount->mount_point);
|
|
|
|
kfree(mount);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err1:
|
|
|
|
mutex_unlock(&vfs_mount_op_mutex);
|
|
|
|
err:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_sync(void)
|
|
|
|
{
|
|
|
|
struct hash_iterator iter;
|
|
|
|
struct fs_mount *mount;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_sync: entry.\n"));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
/* cycle through and call sync on each mounted fs */
|
|
|
|
mutex_lock(&vfs_mount_op_mutex);
|
|
|
|
mutex_lock(&vfs_mount_mutex);
|
|
|
|
|
|
|
|
hash_open(mounts_table, &iter);
|
2002-07-17 11:55:51 +04:00
|
|
|
while ((mount = hash_next(mounts_table, &iter))) {
|
2002-07-09 16:24:59 +04:00
|
|
|
mount->fs->calls->fs_sync(mount->cookie);
|
|
|
|
}
|
|
|
|
hash_close(mounts_table, &iter, false);
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_mount_mutex);
|
|
|
|
mutex_unlock(&vfs_mount_op_mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-14 09:13:20 +04:00
|
|
|
new_file_fd(struct vnode *vnode,file_cookie cookie, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct file_descriptor *descriptor;
|
2002-07-09 16:24:59 +04:00
|
|
|
int fd;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
descriptor = alloc_fd();
|
|
|
|
if (!descriptor)
|
|
|
|
return ENOMEM;
|
|
|
|
|
|
|
|
descriptor->vnode = vnode;
|
|
|
|
descriptor->cookie = cookie;
|
|
|
|
descriptor->ops = &file_ops;
|
|
|
|
descriptor->type = FDTYPE_FILE;
|
|
|
|
|
|
|
|
fd = new_fd(get_current_io_context(kernel), descriptor);
|
|
|
|
if (fd < 0)
|
|
|
|
return ERR_VFS_FD_TABLE_FULL;
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_create(char *path, int omode, int perms, bool kernel)
|
|
|
|
{
|
|
|
|
char filename[SYS_MAX_NAME_LEN];
|
|
|
|
struct vnode *vnode, *newVnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
file_cookie cookie;
|
2002-07-14 09:13:20 +04:00
|
|
|
vnode_id newID;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_create: path '%s', omode %x, perms %d, kernel %d\n", path, omode, perms, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
status = path_to_dir_vnode(path, &vnode, filename, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode,fs_create) == NULL) {
|
|
|
|
status = EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
2002-07-14 09:13:20 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
status = FS_CALL(vnode,fs_create)(vnode->mount->cookie, vnode->priv_vnode, &cookie, &newID, filename, omode, perms);
|
|
|
|
if (status < 0)
|
|
|
|
goto err;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
status = get_vnode(vnode->mount->id,newID,&newVnode,false);
|
|
|
|
if (status < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err1;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
status = new_file_fd(newVnode,cookie,kernel);
|
|
|
|
if (status >= 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
err1:
|
|
|
|
FS_CALL(vnode,fs_close)(newVnode->mount->cookie, newVnode->priv_vnode, cookie);
|
|
|
|
FS_CALL(vnode,fs_free_cookie)(newVnode->mount->cookie, newVnode->priv_vnode, cookie);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
FS_CALL(vnode,fs_unlink)(vnode->mount->cookie, vnode->priv_vnode, filename);
|
|
|
|
dec_vnode_ref_count(newVnode, true, false);
|
|
|
|
|
|
|
|
err:
|
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_open(char *path, int omode, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *descriptor;
|
|
|
|
struct vnode *vnode = NULL;
|
|
|
|
file_cookie cookie;
|
|
|
|
int status;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
FUNCTION(("vfs_open: entry. path = '%s', omode %d, kernel %d\n", path, omode, kernel));
|
|
|
|
|
|
|
|
status = path_to_vnode(path, &vnode, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = FS_CALL(vnode,fs_open)(vnode->mount->cookie, vnode->priv_vnode, &cookie, omode);
|
|
|
|
if (status < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
status = new_file_fd(vnode,cookie,kernel);
|
|
|
|
if (status >= 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
err1:
|
2002-07-14 09:13:20 +04:00
|
|
|
FS_CALL(vnode,fs_close)(vnode->mount->cookie, vnode->priv_vnode, cookie);
|
|
|
|
FS_CALL(vnode,fs_free_cookie)(vnode->mount->cookie, vnode->priv_vnode, cookie);
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
err:
|
2002-07-14 09:13:20 +04:00
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-17 11:55:51 +04:00
|
|
|
file_close(struct file_descriptor *descriptor)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-17 11:55:51 +04:00
|
|
|
struct vnode *vnode = descriptor->vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("file_close(descriptor = %p)\n",descriptor));
|
|
|
|
|
|
|
|
if (FS_CALL(vnode,fs_close))
|
|
|
|
return FS_CALL(vnode,fs_close)(vnode->mount->cookie,vnode->priv_vnode,descriptor->cookie);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
dir_close(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->vnode;
|
|
|
|
|
|
|
|
FUNCTION(("dir_close(descriptor = %p)\n",descriptor));
|
|
|
|
|
|
|
|
if (FS_CALL(vnode,fs_close_dir))
|
|
|
|
return FS_CALL(vnode,fs_close_dir)(vnode->mount->cookie,vnode->priv_vnode,descriptor->cookie);
|
|
|
|
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_fsync(int fd, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *f;
|
|
|
|
struct vnode *v;
|
|
|
|
int err;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_fsync: entry. fd %d kernel %d\n", fd, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
f = get_fd(get_current_io_context(kernel), fd);
|
|
|
|
if (!f)
|
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
|
|
|
|
|
v = f->vnode;
|
|
|
|
err = v->mount->fs->calls->fs_fsync(v->mount->cookie, v->priv_vnode);
|
|
|
|
|
|
|
|
put_fd(f);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t
|
2002-07-14 09:13:20 +04:00
|
|
|
file_read(struct file_descriptor *f, void *buffer, off_t pos, size_t *length)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct vnode *v = f->vnode;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("file_read: buf %p, pos %Ld, len 0x%p\n", buffer, pos, length));
|
2002-07-09 16:24:59 +04:00
|
|
|
return v->mount->fs->calls->fs_read(v->mount->cookie, v->priv_vnode, f->cookie, buffer, pos, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t
|
2002-07-14 09:13:20 +04:00
|
|
|
file_write(struct file_descriptor *f, const void *buffer, off_t pos, size_t *length)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct vnode *v = f->vnode;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("file_write: buf %p, pos %Ld, len 0x%p\n", buffer, pos, length));
|
2002-07-09 16:24:59 +04:00
|
|
|
return v->mount->fs->calls->fs_write(v->mount->cookie, v->priv_vnode, f->cookie, buffer, pos, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
static off_t
|
|
|
|
file_seek(struct file_descriptor *descriptor, off_t pos, int seekType)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = descriptor->vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("file_seek: pos 0x%Ld, seek_type %d\n", pos, seekType));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
return FS_CALL(vnode,fs_seek)(vnode->mount->cookie, vnode->priv_vnode, descriptor->cookie, pos, seekType);
|
2002-07-14 09:13:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_create_dir(char *path, int perms, bool kernel)
|
|
|
|
{
|
|
|
|
char filename[SYS_MAX_NAME_LEN];
|
|
|
|
struct vnode *vnode;
|
|
|
|
vnode_id vnid;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
FUNCTION(("vfs_create_dir: path '%s', perms %d, kernel %d\n", path, perms, kernel));
|
|
|
|
|
|
|
|
status = path_to_dir_vnode(path, &vnode, filename, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode,fs_create_dir))
|
|
|
|
status = FS_CALL(vnode,fs_create_dir)(vnode->mount->cookie, vnode->priv_vnode, filename, perms, &vnid);
|
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_open_dir(char *path, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *descriptor;
|
|
|
|
struct vnode *vnode;
|
|
|
|
file_cookie cookie;
|
|
|
|
int status;
|
|
|
|
int fd;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_open_dir: path = '%s', kernel %d\n", path, kernel));
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
status = path_to_vnode(path, &vnode, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = FS_CALL(vnode,fs_open_dir)(vnode->mount->cookie, vnode->priv_vnode, &cookie);
|
|
|
|
if (status < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
// file is opened, create a fd
|
|
|
|
descriptor = alloc_fd();
|
|
|
|
if (!descriptor) {
|
|
|
|
status = ENOMEM;
|
|
|
|
goto err1;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
descriptor->vnode = vnode;
|
|
|
|
descriptor->cookie = cookie;
|
|
|
|
descriptor->ops = &dir_ops;
|
|
|
|
descriptor->type = FDTYPE_DIR;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
fd = new_fd(get_current_io_context(kernel), descriptor);
|
|
|
|
if (fd < 0) {
|
|
|
|
status = ERR_VFS_FD_TABLE_FULL;
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
err1:
|
|
|
|
FS_CALL(vnode,fs_close_dir)(vnode->mount->cookie,vnode->priv_vnode,cookie);
|
|
|
|
FS_CALL(vnode,fs_free_dir_cookie)(vnode->mount->cookie,vnode->priv_vnode,cookie);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
err:
|
2002-07-14 09:13:20 +04:00
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
2002-07-14 09:13:20 +04:00
|
|
|
dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->vnode;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode,fs_read_dir))
|
|
|
|
return FS_CALL(vnode,fs_read_dir)(vnode->mount->cookie,vnode->priv_vnode,descriptor->cookie,buffer,bufferSize,_count);
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
2002-07-14 09:13:20 +04:00
|
|
|
dir_rewind(struct file_descriptor *descriptor)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->vnode;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode,fs_rewind_dir))
|
|
|
|
return FS_CALL(vnode,fs_rewind_dir)(vnode->mount->cookie,vnode->priv_vnode,descriptor->cookie);
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-14 09:13:20 +04:00
|
|
|
common_ioctl(struct file_descriptor *descriptor, ulong op, void *buffer, size_t length)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = descriptor->vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (FS_CALL(vnode,fs_ioctl))
|
|
|
|
return FS_CALL(vnode,fs_ioctl)(vnode->mount->cookie,vnode->priv_vnode,descriptor->cookie,op,buffer,length);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return EOPNOTSUPP;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_unlink(char *path, bool kernel)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct vnode *v;
|
|
|
|
char filename[SYS_MAX_NAME_LEN];
|
|
|
|
|
|
|
|
FUNCTION(("vfs_unlink: path '%s', kernel %d\n", path, kernel));
|
|
|
|
|
|
|
|
err = path_to_dir_vnode(path, &v, filename, kernel);
|
2002-07-19 08:20:07 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
err = v->mount->fs->calls->fs_unlink(v->mount->cookie, v->priv_vnode, filename);
|
|
|
|
dec_vnode_ref_count(v, true, false);
|
2002-07-19 08:20:07 +04:00
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
err:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_rename(char *path, char *newpath, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *v1, *v2;
|
|
|
|
char filename1[SYS_MAX_NAME_LEN];
|
|
|
|
char filename2[SYS_MAX_NAME_LEN];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = path_to_dir_vnode(path, &v1, filename1, kernel);
|
|
|
|
if (err < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
err = path_to_dir_vnode(newpath, &v2, filename2, kernel);
|
|
|
|
if (err < 0)
|
|
|
|
goto err1;
|
|
|
|
|
|
|
|
if (v1->fsid != v2->fsid) {
|
|
|
|
err = ERR_VFS_CROSS_FS_RENAME;
|
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v1->mount->fs->calls->fs_rename != NULL)
|
|
|
|
err = v1->mount->fs->calls->fs_rename(v1->mount->cookie, v1->priv_vnode, filename1, v2->priv_vnode, filename2);
|
|
|
|
else
|
|
|
|
err = EINVAL;
|
|
|
|
|
|
|
|
err2:
|
|
|
|
dec_vnode_ref_count(v2, true, false);
|
|
|
|
err1:
|
|
|
|
dec_vnode_ref_count(v1, true, false);
|
|
|
|
err:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-14 09:13:20 +04:00
|
|
|
common_read_stat(struct file_descriptor *descriptor, struct stat *stat)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = descriptor->vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("common_read_stat: stat 0x%p\n", stat));
|
2002-07-14 09:13:20 +04:00
|
|
|
return FS_CALL(vnode,fs_read_stat)(vnode->mount->cookie, vnode->priv_vnode, stat);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-14 09:13:20 +04:00
|
|
|
vfs_write_stat(char *path, struct stat *stat, int stat_mask, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_write_stat: path '%s', stat 0x%p, stat_mask %d, kernel %d\n", path, stat, stat_mask, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
status = path_to_vnode(path, &vnode, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (FS_CALL(vnode,fs_write_stat))
|
|
|
|
status = FS_CALL(vnode,fs_write_stat)(vnode->mount->cookie, vnode->priv_vnode, stat, stat_mask);
|
|
|
|
else
|
|
|
|
status = EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode)
|
|
|
|
{
|
|
|
|
struct io_context *ioctx;
|
|
|
|
|
|
|
|
ioctx = get_current_io_context(kernel);
|
|
|
|
*vnode = get_vnode_from_fd(ioctx, fd);
|
|
|
|
|
|
|
|
if (*vnode == NULL)
|
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
|
|
|
|
|
return B_NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_get_vnode_from_path(const char *path, bool kernel, void **vnode)
|
|
|
|
{
|
|
|
|
struct vnode *v;
|
|
|
|
int err;
|
|
|
|
char buf[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
|
|
|
buf[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
err = path_to_vnode(buf, &v, kernel);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
*vnode = v;
|
|
|
|
|
|
|
|
err:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_put_vnode_ptr(void *vnode)
|
|
|
|
{
|
|
|
|
struct vnode *v = vnode;
|
|
|
|
|
|
|
|
put_vnode(v);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ssize_t
|
2002-07-14 09:13:20 +04:00
|
|
|
vfs_can_page(void *_v)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = _v;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_canpage: vnode 0x%p\n", vnode));
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
if (FS_CALL(vnode,fs_can_page))
|
|
|
|
return FS_CALL(vnode,fs_can_page)(vnode->mount->cookie, vnode->priv_vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ssize_t
|
2002-07-14 09:13:20 +04:00
|
|
|
vfs_read_page(void *_v, iovecs *vecs, off_t pos)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = _v;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_readpage: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return FS_CALL(vnode,fs_read_page)(vnode->mount->cookie, vnode->priv_vnode, vecs, pos);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ssize_t
|
2002-07-14 09:13:20 +04:00
|
|
|
vfs_write_page(void *_v, iovecs *vecs, off_t pos)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = _v;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_writepage: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return FS_CALL(vnode,fs_write_page)(vnode->mount->cookie, vnode->priv_vnode, vecs, pos);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-14 09:13:20 +04:00
|
|
|
vfs_get_cwd(char *buffer, size_t size, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
// Get current working directory from io context
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *cwd = get_current_io_context(kernel)->cwd;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_get_cwd: buf %p, size %ld\n", buffer, size));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
if (cwd)
|
2002-07-19 01:06:02 +04:00
|
|
|
return dir_vnode_to_path(cwd, buffer, size);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
return B_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-14 09:13:20 +04:00
|
|
|
vfs_set_cwd(char *path, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
struct io_context *io;
|
|
|
|
struct vnode *vnode = NULL;
|
|
|
|
struct vnode *old_cwd;
|
2002-07-09 16:24:59 +04:00
|
|
|
struct stat stat;
|
|
|
|
int rc;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
FUNCTION(("vfs_set_cwd: path=\'%s\'\n", path));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Get vnode for passed path, and bail if it failed
|
2002-07-14 09:13:20 +04:00
|
|
|
rc = path_to_vnode(path, &vnode, kernel);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
rc = FS_CALL(vnode,fs_read_stat)(vnode->mount->cookie, vnode->priv_vnode, &stat);
|
|
|
|
if (rc < 0)
|
|
|
|
goto err;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (!S_ISDIR(stat.st_mode)) {
|
2002-07-09 16:24:59 +04:00
|
|
|
// nope, can't cwd to here
|
|
|
|
rc = ERR_VFS_WRONG_STREAM_TYPE;
|
2002-07-14 09:13:20 +04:00
|
|
|
goto err;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get current io context and lock
|
2002-07-14 09:13:20 +04:00
|
|
|
io = get_current_io_context(kernel);
|
|
|
|
mutex_lock(&io->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// save the old cwd
|
2002-07-14 09:13:20 +04:00
|
|
|
old_cwd = io->cwd;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Set the new vnode
|
2002-07-14 09:13:20 +04:00
|
|
|
io->cwd = vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Unlock the ioctx
|
2002-07-14 09:13:20 +04:00
|
|
|
mutex_unlock(&io->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Decrease ref count of previous working dir (as the ref is being replaced)
|
|
|
|
if (old_cwd)
|
|
|
|
dec_vnode_ref_count(old_cwd, true, false);
|
|
|
|
|
|
|
|
return B_NO_ERROR;
|
|
|
|
|
|
|
|
err:
|
2002-07-14 09:13:20 +04:00
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_dup(int fd, bool kernel)
|
|
|
|
{
|
|
|
|
struct io_context *io = get_current_io_context(kernel);
|
|
|
|
struct file_descriptor *f;
|
|
|
|
int rc;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_dup: fd = %d\n", fd));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Try to get the fd structure
|
|
|
|
f = get_fd(io, fd);
|
|
|
|
if (!f) {
|
|
|
|
rc = ERR_INVALID_HANDLE;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now put the fd in place
|
|
|
|
rc = new_fd(io, f);
|
|
|
|
|
|
|
|
if (rc < 0)
|
|
|
|
put_fd(f);
|
|
|
|
|
|
|
|
err:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_dup2(int ofd, int nfd, bool kernel)
|
|
|
|
{
|
|
|
|
struct io_context *curr_ioctx;
|
|
|
|
struct file_descriptor *evicted;
|
|
|
|
int rc;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("vfs_dup2: ofd = %d, nfd = %d\n", ofd, nfd));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// quick check
|
|
|
|
if ((ofd < 0) || (nfd < 0)) {
|
|
|
|
rc = ERR_INVALID_HANDLE;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get current io context and lock
|
|
|
|
curr_ioctx = get_current_io_context(kernel);
|
|
|
|
mutex_lock(&curr_ioctx->io_mutex);
|
|
|
|
|
|
|
|
// Check for upper boundary, we do in the locked part
|
|
|
|
// because in the future the fd table might be resizeable
|
|
|
|
if ((ofd >= curr_ioctx->table_size) || !curr_ioctx->fds[ofd]) {
|
|
|
|
rc = ERR_INVALID_HANDLE;
|
|
|
|
goto err_1;
|
|
|
|
}
|
|
|
|
if ((nfd >= curr_ioctx->table_size)) {
|
|
|
|
rc = ERR_INVALID_HANDLE;
|
|
|
|
goto err_1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for identity, note that it cannot be made above
|
|
|
|
// because we always want to return an error on invalid
|
|
|
|
// handles
|
|
|
|
if (ofd == nfd)
|
|
|
|
// ToDo: this is buggy and doesn't unlock the io mutex!
|
|
|
|
goto success;
|
|
|
|
|
|
|
|
// Now do the work
|
|
|
|
evicted = curr_ioctx->fds[nfd];
|
|
|
|
curr_ioctx->fds[nfd] = curr_ioctx->fds[ofd];
|
|
|
|
atomic_add(&curr_ioctx->fds[ofd]->ref_count, 1);
|
|
|
|
|
|
|
|
// Unlock the ioctx
|
|
|
|
mutex_unlock(&curr_ioctx->io_mutex);
|
|
|
|
|
|
|
|
// Say bye bye to the evicted fd
|
|
|
|
if (evicted)
|
|
|
|
put_fd(evicted);
|
|
|
|
|
|
|
|
success:
|
|
|
|
rc = nfd;
|
|
|
|
return nfd;
|
|
|
|
|
|
|
|
err_1:
|
|
|
|
mutex_unlock(&curr_ioctx->io_mutex);
|
|
|
|
err:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
// Calls from within the kernel
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_mount(const char *path, const char *device, const char *fs_name, void *args)
|
|
|
|
{
|
|
|
|
char buf[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
|
|
|
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
|
|
|
buf[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_mount(buf, device, fs_name, args, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_unmount(const char *path)
|
|
|
|
{
|
|
|
|
char buf[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
|
|
|
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
|
|
|
buf[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_unmount(buf, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_sync(void)
|
|
|
|
{
|
|
|
|
return vfs_sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_open(const char *path, int omode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
char buffer[SYS_MAX_PATH_LEN+1];
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
strncpy(buffer, path, SYS_MAX_PATH_LEN);
|
|
|
|
buffer[SYS_MAX_PATH_LEN] = 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return vfs_open(buffer, omode, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_open_dir(const char *path)
|
|
|
|
{
|
|
|
|
char buffer[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
|
|
|
strncpy(buffer, path, SYS_MAX_PATH_LEN);
|
|
|
|
buffer[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_open_dir(buffer, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_fsync(int fd)
|
|
|
|
{
|
|
|
|
return vfs_fsync(fd, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_create(const char *path, int omode, int perms)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
char buffer[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
|
|
|
strncpy(buffer, path, SYS_MAX_PATH_LEN);
|
|
|
|
buffer[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_create(buffer, omode, perms, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_create_dir(const char *path, int perms)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
char buffer[SYS_MAX_PATH_LEN+1];
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
strncpy(buffer, path, SYS_MAX_PATH_LEN);
|
|
|
|
buffer[SYS_MAX_PATH_LEN] = 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return vfs_create_dir(buffer, perms, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_unlink(const char *path)
|
|
|
|
{
|
|
|
|
char buf[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
|
|
|
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
|
|
|
buf[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_unlink(buf, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_rename(const char *oldpath, const char *newpath)
|
|
|
|
{
|
|
|
|
char buf1[SYS_MAX_PATH_LEN+1];
|
|
|
|
char buf2[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
|
|
|
strncpy(buf1, oldpath, SYS_MAX_PATH_LEN);
|
|
|
|
buf1[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
strncpy(buf2, newpath, SYS_MAX_PATH_LEN);
|
|
|
|
buf2[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_rename(buf1, buf2, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_read_stat(const char *path, struct stat *stat)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char buf[SYS_MAX_PATH_LEN+1];
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
|
|
|
buf[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
FUNCTION(("sys_read_stat: path '%s', stat %p,\n", path, stat));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
status = path_to_vnode(buf, &vnode, true);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
status = FS_CALL(vnode,fs_read_stat)(vnode->mount->cookie, vnode->priv_vnode, stat);
|
|
|
|
|
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_write_stat(const char *path, struct stat *stat, int stat_mask)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char buf[SYS_MAX_PATH_LEN+1];
|
|
|
|
|
|
|
|
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
|
|
|
buf[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return vfs_write_stat(buf, stat, stat_mask, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
sys_getcwd(char *buf, size_t size)
|
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int rc;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("sys_getcwd: buf %p, %ld\n", buf, size));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Call vfs to get current working directory
|
|
|
|
rc = vfs_get_cwd(path,SYS_MAX_PATH_LEN-1,true);
|
|
|
|
path[SYS_MAX_PATH_LEN-1] = 0;
|
|
|
|
|
|
|
|
// Copy back the result
|
|
|
|
strncpy(buf,path,size);
|
|
|
|
|
|
|
|
// Return either NULL or the buffer address to indicate failure or success
|
|
|
|
return (rc < 0) ? NULL : buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-17 11:55:51 +04:00
|
|
|
sys_setcwd(const char *_path)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("sys_setcwd: path = %s\n", _path));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Copy new path to kernel space
|
|
|
|
strncpy(path, _path, SYS_MAX_PATH_LEN-1);
|
|
|
|
path[SYS_MAX_PATH_LEN-1] = 0;
|
|
|
|
|
|
|
|
// Call vfs to set new working directory
|
|
|
|
return vfs_set_cwd(path,true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_dup(int fd)
|
|
|
|
{
|
|
|
|
return vfs_dup(fd, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_dup2(int ofd, int nfd)
|
|
|
|
{
|
|
|
|
return vfs_dup2(ofd, nfd, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
// Calls from userland (with extra address checks)
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_mount(const char *upath, const char *udevice, const char *ufs_name, void *args)
|
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN+1];
|
|
|
|
char fs_name[SYS_MAX_OS_NAME_LEN+1];
|
|
|
|
char device[SYS_MAX_PATH_LEN+1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
if ((addr)ufs_name >= KERNEL_BASE && (addr)ufs_name <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
if (udevice != NULL && (addr)udevice >= KERNEL_BASE && (addr)udevice <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
rc = user_strncpy(fs_name, ufs_name, SYS_MAX_OS_NAME_LEN);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
fs_name[SYS_MAX_OS_NAME_LEN] = 0;
|
|
|
|
|
|
|
|
if (udevice) {
|
|
|
|
rc = user_strncpy(device, udevice, SYS_MAX_PATH_LEN);
|
2002-07-19 01:06:02 +04:00
|
|
|
if (rc < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
|
|
|
device[SYS_MAX_PATH_LEN] = 0;
|
2002-07-19 01:06:02 +04:00
|
|
|
} else
|
2002-07-09 16:24:59 +04:00
|
|
|
device[0] = 0;
|
|
|
|
|
|
|
|
return vfs_mount(path, device, fs_name, args, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_unmount(const char *upath)
|
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN+1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_unmount(path, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_sync(void)
|
|
|
|
{
|
|
|
|
return vfs_sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
user_open(const char *upath, int omode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int rc;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN-1] = 0;
|
|
|
|
|
|
|
|
return vfs_open(path, omode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_open_dir(const char *upath)
|
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (rc < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN-1] = 0;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return vfs_open_dir(path, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_fsync(int fd)
|
|
|
|
{
|
|
|
|
return vfs_fsync(fd, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
user_create(const char *upath, int omode, int perms)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-14 09:13:20 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN - 1);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN - 1] = 0;
|
|
|
|
|
|
|
|
return vfs_create(path, omode, perms, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
user_create_dir(const char *upath, int perms)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int rc;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
2002-07-09 16:24:59 +04:00
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN - 1);
|
|
|
|
if (rc < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
2002-07-14 09:13:20 +04:00
|
|
|
path[SYS_MAX_PATH_LEN - 1] = 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return vfs_create_dir(path, perms, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_unlink(const char *upath)
|
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN+1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
|
|
|
if(rc < 0)
|
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_unlink(path, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_rename(const char *uoldpath, const char *unewpath)
|
|
|
|
{
|
|
|
|
char oldpath[SYS_MAX_PATH_LEN+1];
|
|
|
|
char newpath[SYS_MAX_PATH_LEN+1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if((addr)uoldpath >= KERNEL_BASE && (addr)uoldpath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
if((addr)unewpath >= KERNEL_BASE && (addr)unewpath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
rc = user_strncpy(oldpath, uoldpath, SYS_MAX_PATH_LEN);
|
|
|
|
if(rc < 0)
|
|
|
|
return rc;
|
|
|
|
oldpath[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
rc = user_strncpy(newpath, unewpath, SYS_MAX_PATH_LEN);
|
|
|
|
if(rc < 0)
|
|
|
|
return rc;
|
|
|
|
newpath[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
return vfs_rename(oldpath, newpath, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
user_read_stat(const char *upath, struct stat *ustat)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode = NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
struct stat stat;
|
2002-07-14 09:13:20 +04:00
|
|
|
int rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
2002-07-09 16:24:59 +04:00
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if ((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP)
|
2002-07-09 16:24:59 +04:00
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (rc < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN-1] = 0;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
rc = path_to_vnode(path, &vnode, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (FS_CALL(vnode,fs_read_stat))
|
|
|
|
rc = FS_CALL(vnode,fs_read_stat)(vnode->mount->cookie, vnode->priv_vnode, &stat);
|
|
|
|
|
|
|
|
dec_vnode_ref_count(vnode, true, false);
|
|
|
|
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = user_memcpy(ustat, &stat, sizeof(struct stat));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-14 09:13:20 +04:00
|
|
|
user_write_stat(const char *upath, struct stat *ustat, int stat_mask)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN+1];
|
|
|
|
struct stat stat;
|
|
|
|
int rc;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
2002-07-09 16:24:59 +04:00
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if ((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP)
|
2002-07-09 16:24:59 +04:00
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (rc < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
|
|
|
path[SYS_MAX_PATH_LEN] = 0;
|
|
|
|
|
|
|
|
rc = user_memcpy(&stat, ustat, sizeof(struct stat));
|
2002-07-14 09:13:20 +04:00
|
|
|
if (rc < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return vfs_write_stat(path, &stat, stat_mask, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-19 01:06:02 +04:00
|
|
|
user_getcwd(char *buffer, size_t size)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
2002-07-19 01:06:02 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
PRINT(("user_getcwd: buf %p, %ld\n", buffer, size));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Check if userspace address is inside "shared" kernel space
|
2002-07-19 01:06:02 +04:00
|
|
|
if ((addr)buffer >= KERNEL_BASE && (addr)buffer <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Call vfs to get current working directory
|
2002-07-19 01:06:02 +04:00
|
|
|
status = vfs_get_cwd(path, sizeof(path), false);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Copy back the result
|
2002-07-19 01:06:02 +04:00
|
|
|
if (user_strncpy(buffer, path, size) < 0)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-17 11:55:51 +04:00
|
|
|
user_setcwd(const char *upath)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int rc;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
PRINT(("user_setcwd: path = %p\n", upath));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// Check if userspace address is inside "shared" kernel space
|
|
|
|
if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
|
|
|
return ERR_VM_BAD_USER_MEMORY;
|
|
|
|
|
|
|
|
// Copy new path to kernel space
|
|
|
|
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (rc < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return rc;
|
2002-07-17 11:55:51 +04:00
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
path[SYS_MAX_PATH_LEN-1] = 0;
|
|
|
|
|
|
|
|
// Call vfs to set new working directory
|
|
|
|
return vfs_set_cwd(path,false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_dup(int fd)
|
|
|
|
{
|
|
|
|
return vfs_dup(fd, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
user_dup2(int ofd, int nfd)
|
|
|
|
{
|
|
|
|
return vfs_dup2(ofd, nfd, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
vfs_resize_fd_table(struct io_context *ioctx, const int new_size)
|
|
|
|
{
|
|
|
|
void * new_fds;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (new_size < 0 || new_size > MAX_FD_TABLE_SIZE)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
mutex_lock(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
if (new_size < ioctx->table_size) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Make sure none of the fds being dropped are in use */
|
|
|
|
for(i = new_size; i < ioctx->table_size; i++) {
|
|
|
|
if (ioctx->fds[i]) {
|
|
|
|
ret = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
new_fds = kmalloc(sizeof(struct file_descriptor *) * new_size);
|
|
|
|
if (!new_fds) {
|
|
|
|
ret = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(new_fds, ioctx->fds, sizeof(struct file_descriptor *) * new_size);
|
|
|
|
} else {
|
|
|
|
new_fds = kmalloc(sizeof(struct file_descriptor *) * new_size);
|
|
|
|
if (!new_fds) {
|
|
|
|
ret = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(new_fds, ioctx->fds, sizeof(struct file_descriptor *) * ioctx->table_size);
|
|
|
|
memset(((char *)new_fds) + (sizeof(struct file_descriptor *) * ioctx->table_size), 0,
|
|
|
|
(sizeof(struct file_descriptor *) * new_size) - (sizeof(struct file_descriptor *) * ioctx->table_size));
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(ioctx->fds);
|
|
|
|
ioctx->fds = new_fds;
|
|
|
|
ioctx->table_size = new_size;
|
|
|
|
|
|
|
|
mutex_unlock(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
mutex_unlock(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_getrlimit(int resource, struct rlimit * rlp)
|
|
|
|
{
|
|
|
|
if (!rlp) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (resource) {
|
|
|
|
case RLIMIT_NOFILE:
|
|
|
|
{
|
|
|
|
struct io_context *ioctx = get_current_io_context(false);
|
|
|
|
|
|
|
|
mutex_lock(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
rlp->rlim_cur = ioctx->table_size;
|
|
|
|
rlp->rlim_max = MAX_FD_TABLE_SIZE;
|
|
|
|
|
|
|
|
mutex_unlock(&ioctx->io_mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_setrlimit(int resource, const struct rlimit * rlp)
|
|
|
|
{
|
|
|
|
if (!rlp)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (resource) {
|
|
|
|
case RLIMIT_NOFILE:
|
|
|
|
return vfs_resize_fd_table(get_current_io_context(false), rlp->rlim_cur);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_test(void)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
dprintf("vfs_test() entry\n");
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
fd = sys_open_dir("/");
|
2002-07-09 16:24:59 +04:00
|
|
|
dprintf("fd = %d\n", fd);
|
|
|
|
sys_close(fd);
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
fd = sys_open_dir("/");
|
2002-07-09 16:24:59 +04:00
|
|
|
dprintf("fd = %d\n", fd);
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_create_dir("/foo", 0755);
|
|
|
|
sys_create_dir("/foo/bar", 0755);
|
|
|
|
sys_create_dir("/foo/bar/gar", 0755);
|
|
|
|
sys_create_dir("/foo/bar/tar", 0755);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
#if 1
|
2002-07-14 09:13:20 +04:00
|
|
|
fd = sys_open_dir("/foo/bar");
|
|
|
|
if (fd < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("unable to open /foo/bar\n");
|
|
|
|
|
|
|
|
{
|
|
|
|
char buf[64];
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
sys_seek(fd, 0, SEEK_SET);
|
2002-07-14 09:13:20 +04:00
|
|
|
for (;;) {
|
2002-07-09 16:24:59 +04:00
|
|
|
len = sys_read(fd, buf, -1, sizeof(buf));
|
2002-07-17 11:55:51 +04:00
|
|
|
if (len > 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
dprintf("readdir returned name = '%s'\n", buf);
|
|
|
|
else {
|
|
|
|
dprintf("readdir returned %s\n", strerror(len));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// do some unlink tests
|
|
|
|
err = sys_unlink("/foo/bar");
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err == B_NO_ERROR)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("unlink of full directory should not have passed\n");
|
|
|
|
sys_unlink("/foo/bar/gar");
|
|
|
|
sys_unlink("/foo/bar/tar");
|
|
|
|
err = sys_unlink("/foo/bar");
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err != B_NO_ERROR)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("unlink of empty directory should have worked\n");
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_create_dir("/test", 0755);
|
|
|
|
sys_create_dir("/test", 0755);
|
2002-07-09 16:24:59 +04:00
|
|
|
err = sys_mount("/test", NULL, "rootfs", NULL);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("failed mount test\n");
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#if 1
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
fd = sys_open_dir("/boot");
|
2002-07-09 16:24:59 +04:00
|
|
|
sys_close(fd);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
fd = sys_open_dir("/boot");
|
|
|
|
if (fd < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("unable to open dir /boot\n");
|
|
|
|
{
|
2002-07-17 11:55:51 +04:00
|
|
|
char buf[256];
|
|
|
|
struct dirent *dirent = (struct dirent *)buf;
|
2002-07-09 16:24:59 +04:00
|
|
|
ssize_t len;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
sys_rewind_dir(fd);
|
|
|
|
for (;;) {
|
|
|
|
len = sys_read_dir(fd, dirent, sizeof(buf), 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
// if(len < 0)
|
|
|
|
// panic("readdir returned %Ld\n", (long long)len);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (len > 0)
|
|
|
|
dprintf("sys_read returned name = '%s'\n", dirent->d_name);
|
2002-07-09 16:24:59 +04:00
|
|
|
else {
|
|
|
|
dprintf("sys_read returned %s\n", strerror(len));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sys_close(fd);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
fd = sys_open("/boot/kernel", O_RDONLY);
|
|
|
|
if (fd < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("unable to open kernel file '/boot/kernel'\n");
|
|
|
|
{
|
|
|
|
char buf[64];
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
len = sys_read(fd, buf, 0, sizeof(buf));
|
2002-07-17 11:55:51 +04:00
|
|
|
if (len < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("failed on read\n");
|
|
|
|
dprintf("read returned %Ld\n", (long long)len);
|
|
|
|
}
|
|
|
|
sys_close(fd);
|
|
|
|
{
|
|
|
|
struct stat stat;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
err = sys_read_stat("/boot/kernel", &stat);
|
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("err stating '/boot/kernel'\n");
|
|
|
|
dprintf("stat results:\n");
|
|
|
|
dprintf("\tvnid 0x%Lx\n\ttype %d\n\tsize 0x%Lx\n", stat.st_ino, stat.st_mode, stat.st_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
dprintf("vfs_test() done\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
image_id
|
|
|
|
vfs_load_fs_module(const char *name)
|
|
|
|
{
|
|
|
|
image_id id;
|
|
|
|
void (*bootstrap)();
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
|
|
|
|
// sprintf(path, "/boot/addons/fs/%s", name);
|
|
|
|
|
|
|
|
id = elf_load_kspace(path, "");
|
2002-07-17 11:55:51 +04:00
|
|
|
if (id < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
return id;
|
|
|
|
|
|
|
|
bootstrap = (void *)elf_lookup_symbol(id, "fs_bootstrap");
|
2002-07-17 11:55:51 +04:00
|
|
|
if (!bootstrap)
|
2002-07-09 16:24:59 +04:00
|
|
|
return ERR_VFS_INVALID_FS;
|
|
|
|
|
|
|
|
bootstrap();
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_bootstrap_all_filesystems(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
// bootstrap the root filesystem
|
|
|
|
bootstrap_rootfs();
|
|
|
|
|
|
|
|
err = sys_mount("/", NULL, "rootfs", NULL);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("error mounting rootfs!\n");
|
|
|
|
|
|
|
|
sys_setcwd("/");
|
|
|
|
|
|
|
|
// bootstrap the bootfs
|
|
|
|
bootstrap_bootfs();
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_create_dir("/boot",0755);
|
2002-07-09 16:24:59 +04:00
|
|
|
err = sys_mount("/boot", NULL, "bootfs", NULL);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("error mounting bootfs\n");
|
|
|
|
|
|
|
|
// bootstrap the devfs
|
|
|
|
bootstrap_devfs();
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
sys_create_dir("/dev",0755);
|
2002-07-09 16:24:59 +04:00
|
|
|
err = sys_mount("/dev", NULL, "devfs", NULL);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (err < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("error mounting devfs\n");
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
fd = sys_open_dir("/boot/addons/fs");
|
2002-07-09 16:24:59 +04:00
|
|
|
if (fd >= 0) {
|
2002-07-14 09:13:20 +04:00
|
|
|
char buffer[sizeof(struct dirent) + 1 + SYS_MAX_NAME_LEN];
|
|
|
|
struct dirent *dirent = (struct dirent *)buffer;
|
|
|
|
ssize_t length;
|
|
|
|
|
|
|
|
while ((length = sys_read_dir(fd, dirent, sizeof(buffer), 1)) > 0)
|
|
|
|
vfs_load_fs_module(dirent->d_name);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
sys_close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_register_filesystem(const char *name, struct fs_calls *calls)
|
|
|
|
{
|
|
|
|
struct fs_container *container;
|
|
|
|
|
|
|
|
container = (struct fs_container *)kmalloc(sizeof(struct fs_container));
|
2002-07-17 11:55:51 +04:00
|
|
|
if (container == NULL)
|
2002-07-09 16:24:59 +04:00
|
|
|
return ENOMEM;
|
|
|
|
|
|
|
|
container->name = name;
|
|
|
|
container->calls = calls;
|
|
|
|
|
|
|
|
mutex_lock(&vfs_mutex);
|
|
|
|
|
|
|
|
container->next = fs_list;
|
|
|
|
fs_list = container;
|
|
|
|
|
|
|
|
mutex_unlock(&vfs_mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_init(kernel_args *ka)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct vnode *v;
|
|
|
|
vnode_table = hash_init(VNODE_HASH_TABLE_SIZE, (addr)&v->next - (addr)v,
|
|
|
|
&vnode_compare, &vnode_hash);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (vnode_table == NULL)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("vfs_init: error creating vnode hash table\n");
|
|
|
|
}
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
mounts_table = hash_init(MOUNTS_HASH_TABLE_SIZE, (addr)&mount->next - (addr)mount,
|
|
|
|
&mount_compare, &mount_hash);
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mounts_table == NULL)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("vfs_init: error creating mounts hash table\n");
|
|
|
|
}
|
|
|
|
fs_list = NULL;
|
|
|
|
root_vnode = NULL;
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mutex_init(&vfs_mutex, "vfs_lock") < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("vfs_init: error allocating vfs lock\n");
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mutex_init(&vfs_mount_op_mutex, "vfs_mount_op_lock") < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("vfs_init: error allocating vfs_mount_op lock\n");
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mutex_init(&vfs_mount_mutex, "vfs_mount_lock") < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("vfs_init: error allocating vfs_mount lock\n");
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mutex_init(&vfs_vnode_mutex, "vfs_vnode_lock") < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("vfs_init: error allocating vfs_vnode lock\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|