2002-07-09 16:24:59 +04:00
|
|
|
/*
|
|
|
|
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
|
|
|
** Distributed under the terms of the NewOS License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <kernel.h>
|
|
|
|
#include <vfs.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <khash.h>
|
|
|
|
#include <memheap.h>
|
|
|
|
#include <lock.h>
|
|
|
|
#include <vm.h>
|
|
|
|
#include <Errors.h>
|
2002-07-12 02:21:56 +04:00
|
|
|
#include <kerrors.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <arch/cpu.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <bootdir.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2002-09-26 05:13:42 +04:00
|
|
|
#include "bootfs.h"
|
|
|
|
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
#define BOOTFS_TRACE 1
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
#if BOOTFS_TRACE
|
|
|
|
#define TRACE(x) dprintf x
|
|
|
|
#else
|
|
|
|
#define TRACE(x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static char *bootdir = NULL;
|
|
|
|
static off_t bootdir_len = 0;
|
|
|
|
static region_id bootdir_region = -1;
|
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
typedef enum {
|
|
|
|
STREAM_TYPE_FILE = S_IFREG,
|
|
|
|
STREAM_TYPE_DIR = S_IFDIR,
|
|
|
|
} stream_type;
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
struct bootfs_stream {
|
|
|
|
stream_type type;
|
|
|
|
union {
|
|
|
|
struct stream_dir {
|
|
|
|
struct bootfs_vnode *dir_head;
|
|
|
|
struct bootfs_cookie *jar_head;
|
|
|
|
} dir;
|
|
|
|
struct stream_file {
|
|
|
|
void *start;
|
|
|
|
off_t len;
|
|
|
|
} file;
|
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct bootfs_vnode {
|
|
|
|
struct bootfs_vnode *all_next;
|
|
|
|
vnode_id id;
|
|
|
|
char *name;
|
|
|
|
struct bootfs_vnode *parent;
|
|
|
|
struct bootfs_vnode *dir_next;
|
|
|
|
struct bootfs_stream stream;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct bootfs {
|
2002-09-25 18:10:50 +04:00
|
|
|
mount_id id;
|
2002-07-09 16:24:59 +04:00
|
|
|
mutex lock;
|
|
|
|
int next_vnode_id;
|
|
|
|
void *vnode_list_hash;
|
|
|
|
struct bootfs_vnode *root_vnode;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct bootfs_cookie {
|
|
|
|
struct bootfs_stream *s;
|
|
|
|
int oflags;
|
|
|
|
union {
|
|
|
|
struct cookie_dir {
|
|
|
|
struct bootfs_cookie *next;
|
|
|
|
struct bootfs_cookie *prev;
|
|
|
|
struct bootfs_vnode *ptr;
|
|
|
|
} dir;
|
|
|
|
struct cookie_file {
|
|
|
|
off_t pos;
|
|
|
|
} file;
|
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
#define BOOTFS_HASH_SIZE 16
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
bootfs_vnode_hash_func(void *_v, const void *_key, unsigned int range)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
const vnode_id *key = _key;
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
if (v != NULL)
|
2002-07-09 16:24:59 +04:00
|
|
|
return v->id % range;
|
|
|
|
else
|
|
|
|
return (*key) % range;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static int
|
|
|
|
bootfs_vnode_compare_func(void *_v, const void *_key)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
const vnode_id *key = _key;
|
|
|
|
|
|
|
|
if(v->id == *key)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static struct bootfs_vnode *
|
|
|
|
bootfs_create_vnode(struct bootfs *fs, const char *name)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v;
|
|
|
|
|
|
|
|
v = kmalloc(sizeof(struct bootfs_vnode));
|
|
|
|
if(v == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memset(v, 0, sizeof(struct bootfs_vnode));
|
|
|
|
v->id = fs->next_vnode_id++;
|
|
|
|
|
|
|
|
v->name = kstrdup(name);
|
|
|
|
if(v->name == NULL) {
|
|
|
|
kfree(v);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-07-11 01:55:33 +04:00
|
|
|
bootfs_delete_vnode(struct bootfs *fs, struct bootfs_vnode *v, bool force_delete)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
// cant delete it if it's in a directory or is a directory
|
|
|
|
// and has children
|
|
|
|
if(!force_delete && ((v->stream.type == STREAM_TYPE_DIR && v->stream.u.dir.dir_head != NULL) || v->dir_next != NULL)) {
|
2002-07-12 02:21:56 +04:00
|
|
|
return EPERM;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// remove it from the global hash table
|
|
|
|
hash_remove(fs->vnode_list_hash, v);
|
|
|
|
|
|
|
|
if(v->name != NULL)
|
|
|
|
kfree(v->name);
|
|
|
|
kfree(v);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static void
|
|
|
|
insert_cookie_in_jar(struct bootfs_vnode *dir, struct bootfs_cookie *cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
cookie->u.dir.next = dir->stream.u.dir.jar_head;
|
|
|
|
dir->stream.u.dir.jar_head = cookie;
|
|
|
|
cookie->u.dir.prev = NULL;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static void
|
|
|
|
remove_cookie_from_jar(struct bootfs_vnode *dir, struct bootfs_cookie *cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
if(cookie->u.dir.next)
|
|
|
|
cookie->u.dir.next->u.dir.prev = cookie->u.dir.prev;
|
|
|
|
if(cookie->u.dir.prev)
|
|
|
|
cookie->u.dir.prev->u.dir.next = cookie->u.dir.next;
|
|
|
|
if(dir->stream.u.dir.jar_head == cookie)
|
|
|
|
dir->stream.u.dir.jar_head = cookie->u.dir.next;
|
|
|
|
|
|
|
|
cookie->u.dir.prev = cookie->u.dir.next = NULL;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
/** Makes sure none of the dircookies point to the vnode passed in */
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_dircookies(struct bootfs_vnode *dir, struct bootfs_vnode *v)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_cookie *cookie;
|
|
|
|
|
|
|
|
for(cookie = dir->stream.u.dir.jar_head; cookie; cookie = cookie->u.dir.next) {
|
|
|
|
if(cookie->u.dir.ptr == v) {
|
|
|
|
cookie->u.dir.ptr = v->dir_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
static struct bootfs_vnode *
|
|
|
|
bootfs_find_in_dir(struct bootfs_vnode *dir, const char *path)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v;
|
|
|
|
|
|
|
|
if(dir->stream.type != STREAM_TYPE_DIR)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if(!strcmp(path, "."))
|
|
|
|
return dir;
|
|
|
|
if(!strcmp(path, ".."))
|
|
|
|
return dir->parent;
|
|
|
|
|
|
|
|
for(v = dir->stream.u.dir.dir_head; v; v = v->dir_next) {
|
|
|
|
// dprintf("bootfs_find_in_dir: looking at entry '%s'\n", v->name);
|
|
|
|
if(strcmp(v->name, path) == 0) {
|
|
|
|
// dprintf("bootfs_find_in_dir: found it at 0x%x\n", v);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-07-11 01:55:33 +04:00
|
|
|
bootfs_insert_in_dir(struct bootfs_vnode *dir, struct bootfs_vnode *v)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
if(dir->stream.type != STREAM_TYPE_DIR)
|
2002-07-12 02:21:56 +04:00
|
|
|
return EINVAL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
v->dir_next = dir->stream.u.dir.dir_head;
|
|
|
|
dir->stream.u.dir.dir_head = v;
|
|
|
|
|
|
|
|
v->parent = dir;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-07-11 01:55:33 +04:00
|
|
|
bootfs_remove_from_dir(struct bootfs_vnode *dir, struct bootfs_vnode *findit)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v;
|
|
|
|
struct bootfs_vnode *last_v;
|
|
|
|
|
|
|
|
for(v = dir->stream.u.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) {
|
|
|
|
if(v == findit) {
|
|
|
|
/* make sure all dircookies dont point to this vnode */
|
|
|
|
update_dircookies(dir, v);
|
|
|
|
|
|
|
|
if(last_v)
|
|
|
|
last_v->dir_next = v->dir_next;
|
|
|
|
else
|
|
|
|
dir->stream.u.dir.dir_head = v->dir_next;
|
|
|
|
v->dir_next = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
/* XXX seems to be unused
|
|
|
|
static bool
|
2002-07-11 01:55:33 +04:00
|
|
|
bootfs_is_dir_empty(struct bootfs_vnode *dir)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
if(dir->stream.type != STREAM_TYPE_DIR)
|
|
|
|
return false;
|
|
|
|
return !dir->stream.u.dir.dir_head;
|
|
|
|
}
|
2002-09-03 06:19:22 +04:00
|
|
|
*/
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
/** Creates a path of vnodes up to the last part of the passed in path.
|
|
|
|
* returns the vnode the last segment should be a part of and
|
|
|
|
* a pointer to the leaf of the path.
|
|
|
|
* clobbers the path string passed in
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct bootfs_vnode *
|
|
|
|
bootfs_create_path(struct bootfs *fs, char *path, struct bootfs_vnode *base, char **path_leaf)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v;
|
|
|
|
char *temp;
|
|
|
|
bool done;
|
|
|
|
|
|
|
|
// strip off any leading '/' or spaces
|
|
|
|
for(; *path == '/' || *path == ' '; path++)
|
|
|
|
;
|
|
|
|
|
|
|
|
// first, find the leaf
|
|
|
|
*path_leaf = strrchr(path, '/');
|
|
|
|
if(*path_leaf == NULL) {
|
|
|
|
// didn't find it, so this path only is a leaf
|
|
|
|
*path_leaf = path;
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is a multipart path, seperate the leaf off
|
|
|
|
**path_leaf = '\0';
|
|
|
|
(*path_leaf)++;
|
|
|
|
if(**path_leaf == '\0') {
|
|
|
|
// the path ended with '/'. That's invalid
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now, lets walk down the path, building vnodes as we need em
|
|
|
|
done = false;
|
|
|
|
for(; !done; path = temp+1) {
|
|
|
|
// find the next seperator and knock it out
|
|
|
|
temp = strchr(path, '/');
|
|
|
|
if(temp) {
|
|
|
|
*temp = '\0';
|
|
|
|
} else {
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(*path == '\0') {
|
|
|
|
// zero length path segment, continue
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = bootfs_find_in_dir(base, path);
|
|
|
|
if(!v) {
|
|
|
|
v = bootfs_create_vnode(fs, path);
|
|
|
|
if(!v)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
v->stream.type = STREAM_TYPE_DIR;
|
|
|
|
v->stream.u.dir.dir_head = NULL;
|
|
|
|
v->stream.u.dir.jar_head = NULL;
|
|
|
|
|
|
|
|
bootfs_insert_in_dir(base, v);
|
|
|
|
hash_insert(fs->vnode_list_hash, v);
|
|
|
|
} else {
|
|
|
|
// we found one
|
|
|
|
if(v->stream.type != STREAM_TYPE_DIR)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
base = v;
|
|
|
|
}
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-07-11 01:55:33 +04:00
|
|
|
bootfs_create_vnode_tree(struct bootfs *fs, struct bootfs_vnode *root)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
boot_entry *entry;
|
|
|
|
int err;
|
|
|
|
struct bootfs_vnode *new_vnode;
|
|
|
|
struct bootfs_vnode *dir;
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
char *leaf;
|
|
|
|
|
|
|
|
entry = (boot_entry *)bootdir;
|
2002-07-11 01:55:33 +04:00
|
|
|
for (i = 0; i < BOOTDIR_MAX_ENTRIES; i++) {
|
2002-07-09 16:24:59 +04:00
|
|
|
if(entry[i].be_type != BE_TYPE_NONE && entry[i].be_type != BE_TYPE_DIRECTORY) {
|
|
|
|
strncpy(path, entry[i].be_name, SYS_MAX_PATH_LEN-1);
|
|
|
|
path[SYS_MAX_PATH_LEN-1] = '\0';
|
|
|
|
|
|
|
|
dir = bootfs_create_path(fs, path, root, &leaf);
|
|
|
|
if(!dir)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
new_vnode = bootfs_create_vnode(fs, leaf);
|
|
|
|
if(new_vnode == NULL)
|
2002-07-12 02:21:56 +04:00
|
|
|
return ENOMEM;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// set up the new node
|
|
|
|
new_vnode->stream.type = STREAM_TYPE_FILE;
|
|
|
|
new_vnode->stream.u.file.start = bootdir + entry[i].be_offset * PAGE_SIZE;
|
|
|
|
new_vnode->stream.u.file.len = entry[i].be_vsize;
|
|
|
|
|
|
|
|
dprintf("bootfs_create_vnode_tree: added entry '%s', start %p, len 0x%Lx\n", new_vnode->name,
|
|
|
|
new_vnode->stream.u.file.start, new_vnode->stream.u.file.len);
|
|
|
|
|
|
|
|
// insert it into the parent dir
|
|
|
|
bootfs_insert_in_dir(dir, new_vnode);
|
|
|
|
|
|
|
|
hash_insert(fs->vnode_list_hash, new_vnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-25 18:10:50 +04:00
|
|
|
bootfs_mount(mount_id id, const char *device, void *args, fs_volume *_fs, vnode_id *root_vnid)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs;
|
|
|
|
struct bootfs_vnode *v;
|
2002-09-03 06:19:22 +04:00
|
|
|
status_t err;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
TRACE(("bootfs_mount: entry\n"));
|
|
|
|
|
|
|
|
fs = kmalloc(sizeof(struct bootfs));
|
|
|
|
if(fs == NULL) {
|
2002-07-12 02:21:56 +04:00
|
|
|
err = ENOMEM;
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs->id = id;
|
|
|
|
fs->next_vnode_id = 0;
|
|
|
|
|
|
|
|
err = mutex_init(&fs->lock, "bootfs_mutex");
|
|
|
|
if(err < 0) {
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs->vnode_list_hash = hash_init(BOOTFS_HASH_SIZE, (addr)&v->all_next - (addr)v,
|
|
|
|
&bootfs_vnode_compare_func, &bootfs_vnode_hash_func);
|
|
|
|
if(fs->vnode_list_hash == NULL) {
|
2002-07-12 02:21:56 +04:00
|
|
|
err = ENOMEM;
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a vnode
|
|
|
|
v = bootfs_create_vnode(fs, "");
|
|
|
|
if(v == NULL) {
|
2002-07-12 02:21:56 +04:00
|
|
|
err = ENOMEM;
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set it up
|
|
|
|
v->parent = v;
|
|
|
|
|
|
|
|
// create a dir stream for it to hold
|
|
|
|
v->stream.type = STREAM_TYPE_DIR;
|
|
|
|
v->stream.u.dir.dir_head = NULL;
|
|
|
|
fs->root_vnode = v;
|
|
|
|
|
|
|
|
hash_insert(fs->vnode_list_hash, v);
|
|
|
|
|
|
|
|
err = bootfs_create_vnode_tree(fs, fs->root_vnode);
|
|
|
|
if(err < 0) {
|
|
|
|
goto err4;
|
|
|
|
}
|
|
|
|
|
|
|
|
*root_vnid = v->id;
|
|
|
|
*_fs = fs;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err4:
|
|
|
|
bootfs_delete_vnode(fs, v, true);
|
|
|
|
err3:
|
|
|
|
hash_uninit(fs->vnode_list_hash);
|
|
|
|
err2:
|
|
|
|
mutex_destroy(&fs->lock);
|
|
|
|
err1:
|
|
|
|
kfree(fs);
|
|
|
|
err:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_unmount(fs_volume _fs)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v;
|
|
|
|
struct hash_iterator i;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_unmount: entry fs = %p\n", fs));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// delete all of the vnodes
|
|
|
|
hash_open(fs->vnode_list_hash, &i);
|
|
|
|
while((v = (struct bootfs_vnode *)hash_next(fs->vnode_list_hash, &i)) != NULL) {
|
|
|
|
bootfs_delete_vnode(fs, v, true);
|
|
|
|
}
|
|
|
|
hash_close(fs->vnode_list_hash, &i, false);
|
|
|
|
|
|
|
|
hash_uninit(fs->vnode_list_hash);
|
|
|
|
mutex_destroy(&fs->lock);
|
|
|
|
kfree(fs);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_sync(fs_volume fs)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
TRACE(("bootfs_sync: entry\n"));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_lookup(fs_volume _fs, fs_vnode _dir, const char *name, vnode_id *_id, int *_type)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = (struct bootfs *)_fs;
|
|
|
|
struct bootfs_vnode *dir = (struct bootfs_vnode *)_dir;
|
2002-07-28 22:41:07 +04:00
|
|
|
struct bootfs_vnode *vnode, *vdummy;
|
2002-09-03 06:19:22 +04:00
|
|
|
status_t status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_lookup: entry dir %p, name '%s'\n", dir, name));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
if (dir->stream.type != STREAM_TYPE_DIR)
|
2002-07-28 22:41:07 +04:00
|
|
|
return B_NOT_A_DIRECTORY;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
|
|
|
// look it up
|
2002-07-28 22:41:07 +04:00
|
|
|
vnode = bootfs_find_in_dir(dir, name);
|
|
|
|
if (!vnode) {
|
|
|
|
status = B_ENTRY_NOT_FOUND;
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
status = vfs_get_vnode(fs->id, vnode->id, (fs_vnode *)&vdummy);
|
|
|
|
if (status < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
*_id = vnode->id;
|
|
|
|
*_type = dir->stream.type;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
err:
|
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_get_vnode_name(fs_volume _fs, fs_vnode _vnode, char *buffer, size_t bufferSize)
|
2002-07-19 01:06:02 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *vnode = (struct bootfs_vnode *)_vnode;
|
|
|
|
|
|
|
|
TRACE(("devfs_get_vnode_name: vnode = %p\n",vnode));
|
|
|
|
|
|
|
|
strlcpy(buffer,vnode->name,bufferSize);
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_get_vnode(fs_volume _fs, vnode_id id, fs_vnode *v, bool r)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = (struct bootfs *)_fs;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_get_vnode: asking for vnode 0x%Lx, r %d\n", id, r));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
if(!r)
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
|
|
|
*v = hash_lookup(fs->vnode_list_hash, &id);
|
|
|
|
|
|
|
|
if(!r)
|
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_get_vnode: looked it up at %p\n", *v));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
if(*v)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_put_vnode(fs_volume _fs, fs_vnode _v, bool r)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v = (struct bootfs_vnode *)_v;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_put_vnode: entry on vnode 0x%Lx r %d\n", v->id, r));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
return 0; // whatever
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_remove_vnode(fs_volume _fs, fs_vnode _v, bool reenter)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = (struct bootfs *)_fs;
|
|
|
|
struct bootfs_vnode *v = (struct bootfs_vnode *)_v;
|
|
|
|
struct bootfs_vnode dummy;
|
2002-09-03 06:19:22 +04:00
|
|
|
status_t err;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_remove_vnode: remove %p (0x%Lx) r %d\n", v, v->id, reenter));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
if (!reenter)
|
2002-07-09 16:24:59 +04:00
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
if (v->dir_next) {
|
2002-07-09 16:24:59 +04:00
|
|
|
// can't remove node if it's linked to the dir
|
2002-07-23 18:10:12 +04:00
|
|
|
panic("bootfs_remove_vnode: vnode %p asked to be removed is present in dir\n", v);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bootfs_delete_vnode(fs, v, false);
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
|
|
|
err:
|
2002-07-23 18:10:12 +04:00
|
|
|
if (!reenter)
|
2002-07-09 16:24:59 +04:00
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_create(fs_volume _fs, fs_vnode _dir, const char *name, int omode, int perms, fs_cookie *_cookie, vnode_id *new_vnid)
|
2002-07-14 09:13:20 +04:00
|
|
|
{
|
|
|
|
return EROFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_open(fs_volume _fs, fs_vnode _v, int oflags, fs_cookie *_cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
2002-07-14 09:13:20 +04:00
|
|
|
struct bootfs_vnode *vnode = _v;
|
2002-07-09 16:24:59 +04:00
|
|
|
struct bootfs_cookie *cookie;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_open: vnode %p, oflags 0x%x\n", vnode, oflags));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
cookie = kmalloc(sizeof(struct bootfs_cookie));
|
2002-07-14 09:13:20 +04:00
|
|
|
if (cookie == NULL)
|
|
|
|
return ENOMEM;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
cookie->s = &vnode->stream;
|
|
|
|
cookie->u.file.pos = 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
*_cookie = cookie;
|
|
|
|
|
|
|
|
mutex_unlock(&fs->lock);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_close(fs_volume _fs, fs_vnode _v, fs_cookie _cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
struct bootfs_cookie *cookie = _cookie;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_close: entry vnode %p, cookie %p\n", v, cookie));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_free_cookie(fs_volume _fs, fs_vnode _v, fs_cookie _cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
struct bootfs_cookie *cookie = _cookie;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_freecookie: entry vnode %p, cookie %p\n", v, cookie));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
if (cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
kfree(cookie);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_fsync(fs_volume _fs, fs_vnode _v)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static ssize_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_read(fs_volume _fs, fs_vnode _v, fs_cookie _cookie, off_t pos, void *buf, size_t *len)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
struct bootfs_cookie *cookie = _cookie;
|
|
|
|
ssize_t err = 0;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_read: vnode %p, cookie %p, pos 0x%Lx, len 0x%lx\n", v, cookie, pos, *len));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
|
|
|
switch(cookie->s->type) {
|
|
|
|
case STREAM_TYPE_FILE:
|
|
|
|
if(*len <= 0) {
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(pos < 0) {
|
|
|
|
// we'll read where the cookie is at
|
|
|
|
pos = cookie->u.file.pos;
|
|
|
|
}
|
|
|
|
if(pos >= cookie->s->u.file.len) {
|
|
|
|
*len = 0;
|
|
|
|
err = ESPIPE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(pos + *len > cookie->s->u.file.len) {
|
|
|
|
// trim the read
|
|
|
|
*len = cookie->s->u.file.len - pos;
|
|
|
|
}
|
|
|
|
err = user_memcpy(buf, cookie->s->u.file.start + pos, *len);
|
|
|
|
if(err < 0) {
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
cookie->u.file.pos = pos + *len;
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*len = 0;
|
|
|
|
err = EINVAL;
|
|
|
|
}
|
|
|
|
err:
|
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static ssize_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_write(fs_volume fs, fs_vnode v, fs_cookie cookie, off_t pos, const void *buf, size_t *len)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_write: vnode %p, cookie %p, pos 0x%Lx , len 0x%lx\n", v, cookie, pos, *len));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
return EROFS;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
static off_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_seek(fs_volume _fs, fs_vnode _v, fs_cookie _cookie, off_t pos, int seekType)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
struct bootfs_cookie *cookie = _cookie;
|
2002-09-03 06:19:22 +04:00
|
|
|
status_t err = B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_seek: vnode %p, cookie %p, pos 0x%Lx , seek_type %d\n", v, cookie, pos, seekType));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (cookie->s->type != STREAM_TYPE_FILE)
|
|
|
|
return EINVAL;
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
switch (seekType) {
|
|
|
|
case SEEK_SET:
|
|
|
|
if (pos < 0)
|
|
|
|
pos = 0;
|
|
|
|
if (pos > cookie->s->u.file.len)
|
|
|
|
pos = cookie->s->u.file.len;
|
|
|
|
cookie->u.file.pos = pos;
|
2002-07-09 16:24:59 +04:00
|
|
|
break;
|
2002-07-17 11:55:51 +04:00
|
|
|
case SEEK_CUR:
|
|
|
|
if (pos + cookie->u.file.pos > cookie->s->u.file.len)
|
|
|
|
pos = cookie->s->u.file.len;
|
|
|
|
else if (pos + cookie->u.file.pos < 0)
|
|
|
|
pos = 0;
|
|
|
|
else
|
|
|
|
pos += cookie->u.file.pos;
|
|
|
|
break;
|
|
|
|
case SEEK_END:
|
|
|
|
if (pos > 0)
|
|
|
|
pos = cookie->s->u.file.len;
|
|
|
|
else if (pos + cookie->s->u.file.len < 0)
|
|
|
|
pos = 0;
|
|
|
|
else
|
|
|
|
pos += cookie->s->u.file.len;
|
2002-07-09 16:24:59 +04:00
|
|
|
break;
|
|
|
|
default:
|
2002-07-12 02:21:56 +04:00
|
|
|
err = EINVAL;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err == B_OK)
|
|
|
|
cookie->u.file.pos = pos;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (err < B_OK)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return pos;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_create_dir(fs_volume _fs, fs_vnode _dir, const char *name, int perms, vnode_id *new_vnid)
|
2002-07-14 09:13:20 +04:00
|
|
|
{
|
|
|
|
return EROFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_open_dir(fs_volume _fs, fs_vnode _v, fs_cookie *_cookie)
|
2002-07-14 09:13:20 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *vnode = _v;
|
|
|
|
struct bootfs_cookie *cookie;
|
2002-09-03 06:19:22 +04:00
|
|
|
status_t status = 0;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_open_dir: vnode %p\n", vnode));
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
if (vnode->stream.type != STREAM_TYPE_DIR)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
cookie = kmalloc(sizeof(struct bootfs_cookie));
|
|
|
|
if (cookie == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
|
|
|
cookie->s = &vnode->stream;
|
|
|
|
cookie->u.dir.ptr = vnode->stream.u.dir.dir_head;
|
|
|
|
*_cookie = cookie;
|
|
|
|
|
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_read_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-11 01:55:33 +04:00
|
|
|
struct bootfs_cookie *cookie = _cookie;
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
status_t status;
|
|
|
|
|
2002-09-24 03:24:12 +04:00
|
|
|
TRACE(("bootfs_read_dir(fs_volume = %p vnode = %p, fs_cookie = %p, buffer = %p, bufferSize = %ld, num = %ld)\n",_fs, _vnode, cookie, dirent, bufferSize, *_num));
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
|
|
|
if (cookie->u.dir.ptr == NULL) {
|
|
|
|
*_num = 0;
|
|
|
|
status = ENOENT;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
dirent->d_dev = fs->id;
|
|
|
|
dirent->d_ino = cookie->u.dir.ptr->id;
|
|
|
|
dirent->d_reclen = strlen(cookie->u.dir.ptr->name);
|
|
|
|
|
|
|
|
if (sizeof(struct dirent) + dirent->d_reclen + 1 > bufferSize) {
|
2002-07-12 02:21:56 +04:00
|
|
|
status = ENOBUFS;
|
2002-07-11 01:55:33 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = user_strcpy(dirent->d_name, cookie->u.dir.ptr->name);
|
|
|
|
if (status < B_OK)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
cookie->u.dir.ptr = cookie->u.dir.ptr->dir_next;
|
|
|
|
|
|
|
|
err:
|
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_rewind_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-11 01:55:33 +04:00
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *vnode = _vnode;
|
|
|
|
struct bootfs_cookie *cookie = _cookie;
|
|
|
|
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
|
|
|
cookie->u.dir.ptr = vnode->stream.u.dir.dir_head;
|
|
|
|
|
|
|
|
mutex_unlock(&fs->lock);
|
2002-07-09 16:24:59 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_ioctl(fs_volume _fs, fs_vnode _v, fs_cookie _cookie, ulong op, void *buf, size_t len)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-24 03:24:12 +04:00
|
|
|
TRACE(("bootfs_ioctl: fs_volume %p vnode %p, fs_cookie %p, op %lu, buf %p, len %ld\n", _fs, _v, _cookie, op, buf, len));
|
2002-07-09 16:24:59 +04:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_can_page(fs_volume _fs, fs_vnode _v)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_canpage: vnode %p\n", v));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
if (v->stream.type == STREAM_TYPE_FILE)
|
2002-07-09 16:24:59 +04:00
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static ssize_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_read_page(fs_volume _fs, fs_vnode _v, iovecs *vecs, off_t pos)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
unsigned int i;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_readpage: fs_cookie %p vnode %p, vecs %p, pos 0x%Ld\n",fs, v, vecs, pos));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
for (i = 0; i < vecs->num; i++) {
|
|
|
|
if (pos >= v->stream.u.file.len) {
|
2002-07-09 16:24:59 +04:00
|
|
|
memset(vecs->vec[i].iov_base, 0, vecs->vec[i].iov_len);
|
|
|
|
pos += vecs->vec[i].iov_len;
|
|
|
|
} else {
|
|
|
|
unsigned int copy_len;
|
|
|
|
|
|
|
|
copy_len = min(vecs->vec[i].iov_len, v->stream.u.file.len - pos);
|
|
|
|
|
|
|
|
memcpy(vecs->vec[i].iov_base, v->stream.u.file.start + pos, copy_len);
|
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
if (copy_len < vecs->vec[i].iov_len)
|
2002-07-09 16:24:59 +04:00
|
|
|
memset((char *)vecs->vec[i].iov_base + copy_len, 0, vecs->vec[i].iov_len - copy_len);
|
|
|
|
|
|
|
|
pos += vecs->vec[i].iov_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EPERM;
|
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
static ssize_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_write_page(fs_volume _fs, fs_vnode _v, iovecs *vecs, off_t pos)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_writepage: fs_cookie %p vnode %p, vecs %p, pos %Ld \n", fs, v, vecs, pos));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-12 02:21:56 +04:00
|
|
|
return EPERM;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_unlink(fs_volume _fs, fs_vnode _dir, const char *name)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-12 02:21:56 +04:00
|
|
|
return EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_rename(fs_volume _fs, fs_vnode _olddir, const char *oldname, fs_vnode _newdir, const char *newname)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-12 02:21:56 +04:00
|
|
|
return EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_read_stat(fs_volume _fs, fs_vnode _v, struct stat *stat)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
2002-09-03 06:19:22 +04:00
|
|
|
status_t err = 0;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_rstat: fs_cookie %p vnode %p v->id 0x%Lx , stat %p\n", fs, v, v->id, stat));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
mutex_lock(&fs->lock);
|
|
|
|
|
|
|
|
/* Read Only File System */
|
|
|
|
/** XXX - no pretense at access control, just tell people
|
|
|
|
* they can read it :)
|
|
|
|
*/
|
|
|
|
stat->st_mode = (S_IRUSR | S_IRGRP | S_IROTH);
|
|
|
|
stat->st_size = 0;
|
|
|
|
stat->st_ino = v->id;
|
|
|
|
|
|
|
|
switch(v->stream.type) {
|
|
|
|
case STREAM_TYPE_DIR:
|
|
|
|
stat->st_mode |= S_IFDIR;
|
|
|
|
break;
|
|
|
|
case STREAM_TYPE_FILE:
|
|
|
|
stat->st_size = v->stream.u.file.len;
|
|
|
|
stat->st_mode |= S_IFREG;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
err:
|
|
|
|
mutex_unlock(&fs->lock);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
static status_t
|
2002-09-24 03:24:12 +04:00
|
|
|
bootfs_write_stat(fs_volume _fs, fs_vnode _v, const struct stat *stat, int stat_mask)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct bootfs *fs = _fs;
|
|
|
|
struct bootfs_vnode *v = _v;
|
|
|
|
|
2002-08-27 03:34:43 +04:00
|
|
|
TRACE(("bootfs_wstat: fs_cookie %p, vnode %p, v->id 0x%Lx, stat 0x%p, stat_mask 0x%x\n", fs, v, v->id, stat, stat_mask));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// cannot change anything
|
2002-07-12 02:21:56 +04:00
|
|
|
return EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-11 01:55:33 +04:00
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
2002-09-25 20:34:33 +04:00
|
|
|
static struct fs_ops bootfs_ops = {
|
2002-07-09 16:24:59 +04:00
|
|
|
&bootfs_mount,
|
|
|
|
&bootfs_unmount,
|
2002-07-23 18:10:12 +04:00
|
|
|
NULL,
|
|
|
|
NULL,
|
2002-07-09 16:24:59 +04:00
|
|
|
&bootfs_sync,
|
|
|
|
|
|
|
|
&bootfs_lookup,
|
2002-07-19 01:06:02 +04:00
|
|
|
&bootfs_get_vnode_name,
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
&bootfs_get_vnode,
|
|
|
|
&bootfs_put_vnode,
|
|
|
|
&bootfs_remove_vnode,
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
&bootfs_can_page,
|
|
|
|
&bootfs_read_page,
|
|
|
|
&bootfs_write_page,
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
/* common */
|
|
|
|
&bootfs_ioctl,
|
2002-07-09 16:24:59 +04:00
|
|
|
&bootfs_fsync,
|
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
NULL, // read_link
|
2002-08-05 09:37:17 +04:00
|
|
|
NULL, // write_link
|
2002-07-28 22:41:07 +04:00
|
|
|
NULL, // symlink
|
2002-08-14 00:39:25 +04:00
|
|
|
NULL, // link
|
2002-07-14 09:13:20 +04:00
|
|
|
&bootfs_unlink,
|
|
|
|
&bootfs_rename,
|
|
|
|
|
2002-08-13 17:51:36 +04:00
|
|
|
NULL, // access
|
2002-07-14 09:13:20 +04:00
|
|
|
&bootfs_read_stat,
|
|
|
|
&bootfs_write_stat,
|
|
|
|
|
|
|
|
/* file */
|
|
|
|
&bootfs_create,
|
|
|
|
&bootfs_open,
|
|
|
|
&bootfs_close,
|
|
|
|
&bootfs_free_cookie,
|
2002-07-09 16:24:59 +04:00
|
|
|
&bootfs_read,
|
|
|
|
&bootfs_write,
|
|
|
|
&bootfs_seek,
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
/* dir */
|
|
|
|
&bootfs_create_dir,
|
2002-08-14 00:39:25 +04:00
|
|
|
NULL, // remove_dir
|
2002-07-14 09:13:20 +04:00
|
|
|
&bootfs_open_dir,
|
|
|
|
&bootfs_close, // we are using the same operations for directories
|
|
|
|
&bootfs_free_cookie, // and files here - that's intended, not by accident
|
2002-07-09 16:24:59 +04:00
|
|
|
&bootfs_read_dir,
|
|
|
|
&bootfs_rewind_dir,
|
2002-09-24 03:24:12 +04:00
|
|
|
|
|
|
|
// the other operations are not supported (attributes, indices, queries)
|
|
|
|
NULL,
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2002-09-03 06:19:22 +04:00
|
|
|
status_t
|
2002-07-09 16:24:59 +04:00
|
|
|
bootstrap_bootfs(void)
|
|
|
|
{
|
|
|
|
region_id rid;
|
|
|
|
vm_region_info rinfo;
|
|
|
|
|
|
|
|
dprintf("bootstrap_bootfs: entry\n");
|
|
|
|
|
|
|
|
// find the bootdir and set it up
|
|
|
|
rid = vm_find_region_by_name(vm_get_kernel_aspace_id(), "bootdir");
|
2002-07-14 09:13:20 +04:00
|
|
|
if (rid < 0)
|
2002-07-09 16:24:59 +04:00
|
|
|
panic("bootstrap_bootfs: no bootdir area found!\n");
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
vm_get_region_info(rid, &rinfo);
|
|
|
|
bootdir = (char *)rinfo.base;
|
|
|
|
bootdir_len = rinfo.size;
|
|
|
|
bootdir_region = rinfo.id;
|
|
|
|
|
|
|
|
dprintf("bootstrap_bootfs: found bootdir at %p\n", bootdir);
|
|
|
|
|
2002-09-25 20:34:33 +04:00
|
|
|
return vfs_register_filesystem("bootfs", &bootfs_ops);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|