Beginnings of symbolic link support.
Cleanup of the code in many places. Fixed bad bugs in dir_vnode_to_path(), and entry_ref_to_vnode(). Fixed some other bugs. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@509 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+20
-16
@@ -34,6 +34,11 @@ static char *bootdir = NULL;
|
||||
static off_t bootdir_len = 0;
|
||||
static region_id bootdir_region = -1;
|
||||
|
||||
typedef enum {
|
||||
STREAM_TYPE_FILE = S_IFREG,
|
||||
STREAM_TYPE_DIR = S_IFDIR,
|
||||
} stream_type;
|
||||
|
||||
struct bootfs_stream {
|
||||
stream_type type;
|
||||
union {
|
||||
@@ -484,41 +489,38 @@ bootfs_sync(fs_cookie fs)
|
||||
|
||||
|
||||
static int
|
||||
bootfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id)
|
||||
bootfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *_id, int *_type)
|
||||
{
|
||||
struct bootfs *fs = (struct bootfs *)_fs;
|
||||
struct bootfs_vnode *dir = (struct bootfs_vnode *)_dir;
|
||||
struct bootfs_vnode *v;
|
||||
struct bootfs_vnode *v1;
|
||||
int err;
|
||||
struct bootfs_vnode *vnode, *vdummy;
|
||||
int status;
|
||||
|
||||
TRACE(("bootfs_lookup: entry dir 0x%x, name '%s'\n", dir, name));
|
||||
|
||||
if (dir->stream.type != STREAM_TYPE_DIR)
|
||||
return ENOTDIR;
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
// look it up
|
||||
v = bootfs_find_in_dir(dir, name);
|
||||
if (!v) {
|
||||
err = ENOENT;
|
||||
vnode = bootfs_find_in_dir(dir, name);
|
||||
if (!vnode) {
|
||||
status = B_ENTRY_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = vfs_get_vnode(fs->id, v->id, (fs_vnode *)&v1);
|
||||
if(err < 0) {
|
||||
status = vfs_get_vnode(fs->id, vnode->id, (fs_vnode *)&vdummy);
|
||||
if (status < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
*id = v->id;
|
||||
|
||||
err = B_NO_ERROR;
|
||||
*_id = vnode->id;
|
||||
*_type = dir->stream.type;
|
||||
|
||||
err:
|
||||
mutex_unlock(&fs->lock);
|
||||
|
||||
return err;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -989,7 +991,7 @@ err:
|
||||
|
||||
|
||||
static int
|
||||
bootfs_write_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask)
|
||||
bootfs_write_stat(fs_cookie _fs, fs_vnode _v, const struct stat *stat, int stat_mask)
|
||||
{
|
||||
struct bootfs *fs = _fs;
|
||||
struct bootfs_vnode *v = _v;
|
||||
@@ -1026,6 +1028,8 @@ static struct fs_calls bootfs_calls = {
|
||||
&bootfs_ioctl,
|
||||
&bootfs_fsync,
|
||||
|
||||
NULL, // read_link
|
||||
NULL, // symlink
|
||||
&bootfs_unlink,
|
||||
&bootfs_rename,
|
||||
|
||||
|
||||
+31
-24
@@ -34,6 +34,12 @@
|
||||
# define INSANE(x)
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
STREAM_TYPE_DIR = S_IFDIR,
|
||||
STREAM_TYPE_DEVICE = S_IFCHR,
|
||||
STREAM_TYPE_SYMLINK = S_IFLNK
|
||||
} stream_type;
|
||||
|
||||
struct devfs_part_map {
|
||||
off_t offset;
|
||||
off_t size;
|
||||
@@ -57,6 +63,9 @@ struct devfs_stream {
|
||||
device_hooks *calls;
|
||||
struct devfs_part_map *part_map;
|
||||
} dev;
|
||||
struct stream_symlink {
|
||||
char *path;
|
||||
} symlink;
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -502,25 +511,24 @@ devfs_sync(fs_cookie fs)
|
||||
|
||||
|
||||
static int
|
||||
devfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id)
|
||||
devfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *_id, int *_type)
|
||||
{
|
||||
struct devfs *fs = (struct devfs *)_fs;
|
||||
struct devfs_vnode *dir = (struct devfs_vnode *)_dir;
|
||||
struct devfs_vnode *vnode;
|
||||
struct devfs_vnode *vdummy;
|
||||
struct devfs_vnode *vnode, *vdummy;
|
||||
int err;
|
||||
|
||||
TRACE(("devfs_lookup: entry dir %p, name '%s'\n", dir, name));
|
||||
|
||||
if (dir->stream.type != STREAM_TYPE_DIR)
|
||||
return ENOTDIR;
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
// look it up
|
||||
vnode = devfs_find_in_dir(dir, name);
|
||||
if (!vnode) {
|
||||
err = ERR_NOT_FOUND;
|
||||
err = B_ENTRY_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -528,7 +536,8 @@ devfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id)
|
||||
if (err < 0)
|
||||
goto err;
|
||||
|
||||
*id = vnode->id;
|
||||
*_id = vnode->id;
|
||||
*_type = vnode->stream.type;
|
||||
|
||||
err:
|
||||
mutex_unlock(&fs->lock);
|
||||
@@ -967,33 +976,33 @@ devfs_unlink(fs_cookie _fs, fs_vnode _dir, const char *name)
|
||||
{
|
||||
struct devfs *fs = _fs;
|
||||
struct devfs_vnode *dir = _dir;
|
||||
struct devfs_vnode *v;
|
||||
int res = B_NO_ERROR;
|
||||
struct devfs_vnode *vnode;
|
||||
int status = B_NO_ERROR;
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
v = devfs_find_in_dir( dir, name );
|
||||
if(!v) {
|
||||
res = ERR_NOT_FOUND;
|
||||
vnode = devfs_find_in_dir(dir, name);
|
||||
if (!vnode) {
|
||||
status = B_ENTRY_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
// you can unlink partitions only
|
||||
if( v->stream.type != STREAM_TYPE_DEVICE || !v->stream.u.dev.part_map ) {
|
||||
res = EROFS;
|
||||
if (vnode->stream.type != STREAM_TYPE_DEVICE || !vnode->stream.u.dev.part_map) {
|
||||
status = EROFS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = devfs_remove_from_dir( v->parent, v );
|
||||
if( res )
|
||||
status = devfs_remove_from_dir(vnode->parent, vnode);
|
||||
if (status < 0)
|
||||
goto err;
|
||||
|
||||
res = vfs_remove_vnode( fs->id, v->id );
|
||||
status = vfs_remove_vnode(fs->id, vnode->id);
|
||||
|
||||
err:
|
||||
mutex_unlock(&fs->lock);
|
||||
|
||||
return res;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -1012,20 +1021,16 @@ devfs_read_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat)
|
||||
TRACE(("devfs_rstat: vnode %p (%Ld), stat %p\n", vnode, vnode->id, stat));
|
||||
|
||||
stat->st_ino = vnode->id;
|
||||
stat->st_mode = DEFFILEMODE;
|
||||
stat->st_size = 0;
|
||||
|
||||
if (vnode->stream.type == STREAM_TYPE_DIR)
|
||||
stat->st_mode |= S_IFDIR;
|
||||
else
|
||||
stat->st_mode |= S_IFCHR;
|
||||
// ToDo: or should this be just DEFFILEMODE (0666 instead of 0644)?
|
||||
stat->st_mode = vnode->stream.type | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
devfs_write_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask)
|
||||
devfs_write_stat(fs_cookie _fs, fs_vnode _v, const struct stat *stat, int stat_mask)
|
||||
{
|
||||
#if DEVFS_TRACE
|
||||
struct devfs_vnode *v = _v;
|
||||
@@ -1062,6 +1067,8 @@ static struct fs_calls devfs_calls = {
|
||||
&devfs_ioctl,
|
||||
&devfs_fsync,
|
||||
|
||||
NULL, // read_link
|
||||
NULL, // symlink
|
||||
&devfs_unlink,
|
||||
&devfs_rename,
|
||||
|
||||
|
||||
+210
-119
@@ -27,12 +27,21 @@
|
||||
#define TRACE(x)
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
STREAM_TYPE_DIR = S_IFDIR,
|
||||
STREAM_TYPE_SYMLINK = S_IFLNK,
|
||||
} stream_type;
|
||||
|
||||
struct rootfs_stream {
|
||||
// only type of stream supported by rootfs
|
||||
stream_type type;
|
||||
struct stream_dir {
|
||||
struct rootfs_vnode *dir_head;
|
||||
struct rootfs_cookie *jar_head;
|
||||
} dir;
|
||||
struct stream_symlink {
|
||||
char *path;
|
||||
int length;
|
||||
} symlink;
|
||||
};
|
||||
|
||||
struct rootfs_vnode {
|
||||
@@ -67,13 +76,13 @@ struct rootfs_cookie {
|
||||
static unsigned int
|
||||
rootfs_vnode_hash_func(void *_v, const void *_key, unsigned int range)
|
||||
{
|
||||
struct rootfs_vnode *v = _v;
|
||||
struct rootfs_vnode *vnode = _v;
|
||||
const vnode_id *key = _key;
|
||||
|
||||
if(v != NULL)
|
||||
return v->id % range;
|
||||
else
|
||||
return (*key) % range;
|
||||
if (vnode != NULL)
|
||||
return vnode->id % range;
|
||||
|
||||
return (*key) % range;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,10 +92,10 @@ rootfs_vnode_compare_func(void *_v, const void *_key)
|
||||
struct rootfs_vnode *v = _v;
|
||||
const vnode_id *key = _key;
|
||||
|
||||
if(v->id == *key)
|
||||
if (v->id == *key)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,14 +133,18 @@ rootfs_delete_vnode(struct rootfs *fs, struct rootfs_vnode *v, bool force_delete
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void insert_cookie_in_jar(struct rootfs_vnode *dir, struct rootfs_cookie *cookie)
|
||||
|
||||
static void
|
||||
insert_cookie_in_jar(struct rootfs_vnode *dir, struct rootfs_cookie *cookie)
|
||||
{
|
||||
cookie->next = dir->stream.dir.jar_head;
|
||||
dir->stream.dir.jar_head = cookie;
|
||||
cookie->prev = NULL;
|
||||
}
|
||||
|
||||
static void remove_cookie_from_jar(struct rootfs_vnode *dir, struct rootfs_cookie *cookie)
|
||||
|
||||
static void
|
||||
remove_cookie_from_jar(struct rootfs_vnode *dir, struct rootfs_cookie *cookie)
|
||||
{
|
||||
if(cookie->next)
|
||||
cookie->next->prev = cookie->prev;
|
||||
@@ -148,48 +161,52 @@ static void update_dircookies(struct rootfs_vnode *dir, struct rootfs_vnode *v)
|
||||
{
|
||||
struct rootfs_cookie *cookie;
|
||||
|
||||
for(cookie = dir->stream.dir.jar_head; cookie; cookie = cookie->next) {
|
||||
if(cookie->ptr == v) {
|
||||
for (cookie = dir->stream.dir.jar_head; cookie; cookie = cookie->next) {
|
||||
if(cookie->ptr == v)
|
||||
cookie->ptr = v->dir_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct rootfs_vnode *rootfs_find_in_dir(struct rootfs_vnode *dir, const char *path)
|
||||
|
||||
static struct rootfs_vnode *
|
||||
rootfs_find_in_dir(struct rootfs_vnode *dir, const char *path)
|
||||
{
|
||||
struct rootfs_vnode *v;
|
||||
|
||||
if(!strcmp(path, "."))
|
||||
if (!strcmp(path, "."))
|
||||
return dir;
|
||||
if(!strcmp(path, ".."))
|
||||
if (!strcmp(path, ".."))
|
||||
return dir->parent;
|
||||
|
||||
for(v = dir->stream.dir.dir_head; v; v = v->dir_next) {
|
||||
if(strcmp(v->name, path) == 0) {
|
||||
for (v = dir->stream.dir.dir_head; v; v = v->dir_next) {
|
||||
if (strcmp(v->name, path) == 0)
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rootfs_insert_in_dir(struct rootfs_vnode *dir, struct rootfs_vnode *v)
|
||||
|
||||
static int
|
||||
rootfs_insert_in_dir(struct rootfs_vnode *dir, struct rootfs_vnode *v)
|
||||
{
|
||||
v->dir_next = dir->stream.dir.dir_head;
|
||||
dir->stream.dir.dir_head = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rootfs_remove_from_dir(struct rootfs_vnode *dir, struct rootfs_vnode *findit)
|
||||
|
||||
static int
|
||||
rootfs_remove_from_dir(struct rootfs_vnode *dir, struct rootfs_vnode *findit)
|
||||
{
|
||||
struct rootfs_vnode *v;
|
||||
struct rootfs_vnode *last_v;
|
||||
|
||||
for(v = dir->stream.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) {
|
||||
if(v == findit) {
|
||||
for (v = dir->stream.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)
|
||||
if (last_v)
|
||||
last_v->dir_next = v->dir_next;
|
||||
else
|
||||
dir->stream.dir.dir_head = v->dir_next;
|
||||
@@ -228,9 +245,8 @@ rootfs_mount(fs_id id, const char *device, void *args, fs_cookie *_fs, vnode_id
|
||||
fs->next_vnode_id = 0;
|
||||
|
||||
err = mutex_init(&fs->lock, "rootfs_mutex");
|
||||
if(err < 0) {
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
fs->vnode_list_hash = hash_init(ROOTFS_HASH_SIZE, (addr)&v->all_next - (addr)v,
|
||||
&rootfs_vnode_compare_func, &rootfs_vnode_hash_func);
|
||||
@@ -313,38 +329,38 @@ rootfs_sync(fs_cookie fs)
|
||||
|
||||
|
||||
static int
|
||||
rootfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id)
|
||||
rootfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *_id, int *_type)
|
||||
{
|
||||
struct rootfs *fs = (struct rootfs *)_fs;
|
||||
struct rootfs_vnode *dir = (struct rootfs_vnode *)_dir;
|
||||
struct rootfs_vnode *v;
|
||||
struct rootfs_vnode *vnode,*vdummy;
|
||||
struct rootfs_vnode *v1;
|
||||
int err;
|
||||
int status;
|
||||
|
||||
TRACE(("rootfs_lookup: entry dir 0x%x, name '%s'\n", dir, name));
|
||||
if (dir->stream.type != STREAM_TYPE_DIR)
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
// look it up
|
||||
v = rootfs_find_in_dir(dir, name);
|
||||
if(!v) {
|
||||
err = ENOENT;
|
||||
vnode = rootfs_find_in_dir(dir, name);
|
||||
if (!vnode) {
|
||||
status = B_ENTRY_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = vfs_get_vnode(fs->id, v->id, (fs_vnode *)&v1);
|
||||
if(err < 0) {
|
||||
status = vfs_get_vnode(fs->id, vnode->id, (fs_vnode *)&vdummy);
|
||||
if (status < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
*id = v->id;
|
||||
|
||||
err = B_NO_ERROR;
|
||||
*_id = vnode->id;
|
||||
*_type = vnode->stream.type;
|
||||
|
||||
err:
|
||||
mutex_unlock(&fs->lock);
|
||||
|
||||
return err;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -361,23 +377,23 @@ rootfs_get_vnode_name(fs_cookie _fs, fs_vnode _vnode, char *buffer, size_t buffe
|
||||
|
||||
|
||||
static int
|
||||
rootfs_get_vnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r)
|
||||
rootfs_get_vnode(fs_cookie _fs, vnode_id id, fs_vnode *_vnode, bool reenter)
|
||||
{
|
||||
struct rootfs *fs = (struct rootfs *)_fs;
|
||||
|
||||
TRACE(("rootfs_getvnode: asking for vnode 0x%x 0x%x, r %d\n", id, r));
|
||||
TRACE(("rootfs_getvnode: asking for vnode 0x%x 0x%x, r %d\n", id, reenter));
|
||||
|
||||
if (!r)
|
||||
if (!reenter)
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
*v = hash_lookup(fs->vnode_list_hash, &id);
|
||||
*_vnode = hash_lookup(fs->vnode_list_hash, &id);
|
||||
|
||||
if (!r)
|
||||
if (!reenter)
|
||||
mutex_unlock(&fs->lock);
|
||||
|
||||
TRACE(("rootfs_getnvnode: looked it up at 0x%x\n", *v));
|
||||
TRACE(("rootfs_getnvnode: looked it up at 0x%x\n", *_vnode));
|
||||
|
||||
if (*v)
|
||||
if (*_vnode)
|
||||
return B_NO_ERROR;
|
||||
|
||||
return ENOENT;
|
||||
@@ -385,42 +401,39 @@ rootfs_get_vnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r)
|
||||
|
||||
|
||||
static int
|
||||
rootfs_put_vnode(fs_cookie _fs, fs_vnode _v, bool r)
|
||||
rootfs_put_vnode(fs_cookie _fs, fs_vnode _vnode, bool reenter)
|
||||
{
|
||||
#if ROOTFS_TRACE
|
||||
struct rootfs_vnode *v = (struct rootfs_vnode *)_v;
|
||||
struct rootfs_vnode *vnode = (struct rootfs_vnode *)_vnode;
|
||||
|
||||
TRACE(("rootfs_putvnode: entry on vnode 0x%x 0x%x, r %d\n", v->id, r));
|
||||
TRACE(("rootfs_putvnode: entry on vnode 0x%x 0x%x, r %d\n", vnode->id, reenter));
|
||||
#endif
|
||||
return 0; // whatever
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rootfs_remove_vnode(fs_cookie _fs, fs_vnode _v, bool r)
|
||||
rootfs_remove_vnode(fs_cookie _fs, fs_vnode _vnode, bool reenter)
|
||||
{
|
||||
struct rootfs *fs = (struct rootfs *)_fs;
|
||||
struct rootfs_vnode *v = (struct rootfs_vnode *)_v;
|
||||
int err;
|
||||
struct rootfs_vnode *vnode = (struct rootfs_vnode *)_vnode;
|
||||
|
||||
TRACE(("rootfs_removevnode: remove 0x%x (0x%x 0x%x), r %d\n", v, v->id, r));
|
||||
TRACE(("rootfs_removevnode: remove 0x%x (0x%x 0x%x), r %d\n", vnode, vnode->id, reenter));
|
||||
|
||||
if(!r)
|
||||
if (!reenter)
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
if(v->dir_next) {
|
||||
if (vnode->dir_next) {
|
||||
// can't remove node if it's linked to the dir
|
||||
panic("rootfs_removevnode: vnode %p asked to be removed is present in dir\n", v);
|
||||
panic("rootfs_removevnode: vnode %p asked to be removed is present in dir\n", vnode);
|
||||
}
|
||||
|
||||
rootfs_delete_vnode(fs, v, false);
|
||||
rootfs_delete_vnode(fs, vnode, false);
|
||||
|
||||
err = 0;
|
||||
|
||||
if (!r)
|
||||
if (!reenter)
|
||||
mutex_unlock(&fs->lock);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -503,54 +516,51 @@ rootfs_create_dir(fs_cookie _fs, fs_vnode _dir, const char *name, int perms, vno
|
||||
{
|
||||
struct rootfs *fs = _fs;
|
||||
struct rootfs_vnode *dir = _dir;
|
||||
struct rootfs_vnode *new_vnode;
|
||||
struct rootfs_stream *s;
|
||||
int err = 0;
|
||||
struct rootfs_vnode *vnode;
|
||||
bool created_vnode = false;
|
||||
int status = 0;
|
||||
|
||||
TRACE(("rootfs_create: dir 0x%x, name = '%s', stream_type = %d\n", dir, name, st));
|
||||
TRACE(("rootfs_create_dir: dir 0x%x, name = '%s', stream_type = %d\n", dir, name, st));
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
new_vnode = rootfs_find_in_dir(dir, name);
|
||||
if (new_vnode == NULL) {
|
||||
dprintf("rootfs_create: creating new vnode\n");
|
||||
new_vnode = rootfs_create_vnode(fs);
|
||||
if (new_vnode == NULL) {
|
||||
err = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
created_vnode = true;
|
||||
new_vnode->name = kstrdup(name);
|
||||
if (new_vnode->name == NULL) {
|
||||
err = ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
new_vnode->parent = dir;
|
||||
rootfs_insert_in_dir(dir, new_vnode);
|
||||
|
||||
hash_insert(fs->vnode_list_hash, new_vnode);
|
||||
|
||||
s = &new_vnode->stream;
|
||||
} else {
|
||||
// we found the vnode
|
||||
err = ERR_VFS_ALREADY_EXISTS;
|
||||
vnode = rootfs_find_in_dir(dir, name);
|
||||
if (vnode != NULL) {
|
||||
status = B_FILE_EXISTS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
new_vnode->stream.dir.dir_head = NULL;
|
||||
new_vnode->stream.dir.jar_head = NULL;
|
||||
dprintf("rootfs_create: creating new vnode\n");
|
||||
vnode = rootfs_create_vnode(fs);
|
||||
if (vnode == NULL) {
|
||||
status = B_NO_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
created_vnode = true;
|
||||
vnode->name = kstrdup(name);
|
||||
if (vnode->name == NULL) {
|
||||
status = B_NO_MEMORY;
|
||||
goto err1;
|
||||
}
|
||||
vnode->stream.type = STREAM_TYPE_DIR;
|
||||
vnode->parent = dir;
|
||||
rootfs_insert_in_dir(dir, vnode);
|
||||
|
||||
hash_insert(fs->vnode_list_hash, vnode);
|
||||
|
||||
vnode->stream.dir.dir_head = NULL;
|
||||
vnode->stream.dir.jar_head = NULL;
|
||||
|
||||
mutex_unlock(&fs->lock);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
if (created_vnode)
|
||||
rootfs_delete_vnode(fs, new_vnode, false);
|
||||
rootfs_delete_vnode(fs, vnode, false);
|
||||
err:
|
||||
mutex_unlock(&fs->lock);
|
||||
|
||||
return err;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -563,9 +573,12 @@ rootfs_open_dir(fs_cookie _fs, fs_vnode _v, file_cookie *_cookie)
|
||||
|
||||
TRACE(("rootfs_open: vnode 0x%x\n", vnode));
|
||||
|
||||
if (vnode->stream.type != STREAM_TYPE_DIR)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
cookie = kmalloc(sizeof(struct rootfs_cookie));
|
||||
if (cookie == NULL)
|
||||
return ENOMEM;
|
||||
return B_NO_MEMORY;
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
@@ -593,6 +606,7 @@ rootfs_read_dir(fs_cookie _fs, fs_vnode _vnode, file_cookie _cookie, struct dire
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
if (cookie->ptr == NULL) {
|
||||
// we're at the end of the directory
|
||||
*_num = 0;
|
||||
status = B_OK;
|
||||
goto err;
|
||||
@@ -666,44 +680,119 @@ rootfs_write_page(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rootfs_read_link(fs_cookie _fs, fs_vnode _link, char *buffer, size_t bufferSize)
|
||||
{
|
||||
struct rootfs *fs = _fs;
|
||||
struct rootfs_vnode *link = _link;
|
||||
|
||||
if (link->stream.type != STREAM_TYPE_SYMLINK)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (bufferSize < link->stream.symlink.length)
|
||||
return B_NAME_TOO_LONG;
|
||||
|
||||
memcpy(buffer, link->stream.symlink.path, link->stream.symlink.length + 1);
|
||||
return link->stream.symlink.length;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rootfs_symlink(fs_cookie _fs, fs_vnode _dir, const char *name, const char *path)
|
||||
{
|
||||
struct rootfs *fs = _fs;
|
||||
struct rootfs_vnode *dir = _dir;
|
||||
struct rootfs_vnode *vnode;
|
||||
bool created_vnode = false;
|
||||
int status = 0;
|
||||
|
||||
TRACE(("rootfs_symlink: dir 0x%x, name = '%s', path = %s\n", dir, name, path));
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
vnode = rootfs_find_in_dir(dir, name);
|
||||
if (vnode != NULL) {
|
||||
status = B_FILE_EXISTS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dprintf("rootfs_create: creating new symlink\n");
|
||||
vnode = rootfs_create_vnode(fs);
|
||||
if (vnode == NULL) {
|
||||
status = B_NO_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
created_vnode = true;
|
||||
vnode->name = kstrdup(name);
|
||||
if (vnode->name == NULL) {
|
||||
status = B_NO_MEMORY;
|
||||
goto err1;
|
||||
}
|
||||
vnode->stream.type = STREAM_TYPE_SYMLINK;
|
||||
vnode->parent = dir;
|
||||
rootfs_insert_in_dir(dir, vnode);
|
||||
|
||||
hash_insert(fs->vnode_list_hash, vnode);
|
||||
|
||||
vnode->stream.symlink.path = kstrdup(path);
|
||||
if (vnode->stream.symlink.path == NULL) {
|
||||
status = ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
vnode->stream.symlink.length = strlen(path);
|
||||
|
||||
mutex_unlock(&fs->lock);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
if (created_vnode)
|
||||
rootfs_delete_vnode(fs, vnode, false);
|
||||
err:
|
||||
mutex_unlock(&fs->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rootfs_unlink(fs_cookie _fs, fs_vnode _dir, const char *name)
|
||||
{
|
||||
struct rootfs *fs = _fs;
|
||||
struct rootfs_vnode *dir = _dir;
|
||||
struct rootfs_vnode *v;
|
||||
int err;
|
||||
struct rootfs_vnode *vnode;
|
||||
int status;
|
||||
|
||||
TRACE(("rootfs_unlink: dir 0x%x (0x%x 0x%x), name '%s'\n", dir, dir->id, name));
|
||||
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
v = rootfs_find_in_dir(dir, name);
|
||||
if(!v) {
|
||||
err = ERR_VFS_PATH_NOT_FOUND;
|
||||
vnode = rootfs_find_in_dir(dir, name);
|
||||
if (!vnode) {
|
||||
status = B_ENTRY_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
// do some checking to see if we can delete it
|
||||
if(!rootfs_is_dir_empty(v)) {
|
||||
err = ERR_VFS_DIR_NOT_EMPTY;
|
||||
// if the node is a directory, only delete it if it's empty
|
||||
if (vnode->stream.type == STREAM_TYPE_DIR && !rootfs_is_dir_empty(vnode)) {
|
||||
status = B_DIRECTORY_NOT_EMPTY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rootfs_remove_from_dir(dir, v);
|
||||
rootfs_remove_from_dir(dir, vnode);
|
||||
|
||||
// schedule this vnode to be removed when it's ref goes to zero
|
||||
vfs_remove_vnode(fs->id, v->id);
|
||||
vfs_remove_vnode(fs->id, vnode->id);
|
||||
|
||||
err = 0;
|
||||
status = 0;
|
||||
|
||||
err:
|
||||
mutex_unlock(&fs->lock);
|
||||
|
||||
return err;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int rootfs_rename(fs_cookie _fs, fs_vnode _olddir, const char *oldname, fs_vnode _newdir, const char *newname)
|
||||
|
||||
static int
|
||||
rootfs_rename(fs_cookie _fs, fs_vnode _olddir, const char *oldname, fs_vnode _newdir, const char *newname)
|
||||
{
|
||||
struct rootfs *fs = _fs;
|
||||
struct rootfs_vnode *olddir = _olddir;
|
||||
@@ -717,23 +806,23 @@ static int rootfs_rename(fs_cookie _fs, fs_vnode _olddir, const char *oldname, f
|
||||
mutex_lock(&fs->lock);
|
||||
|
||||
v1 = rootfs_find_in_dir(olddir, oldname);
|
||||
if(!v1) {
|
||||
if (!v1) {
|
||||
err = ERR_VFS_PATH_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
v2 = rootfs_find_in_dir(newdir, newname);
|
||||
|
||||
if(olddir == newdir) {
|
||||
if (olddir == newdir) {
|
||||
// rename to a different name in the same dir
|
||||
if(v2) {
|
||||
if (v2) {
|
||||
// target node exists
|
||||
err = ERR_VFS_ALREADY_EXISTS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
// change the name on this node
|
||||
if(strlen(oldname) >= strlen(newname)) {
|
||||
if (strlen(oldname) >= strlen(newname)) {
|
||||
// reuse the old name buffer
|
||||
strcpy(v1->name, newname);
|
||||
} else {
|
||||
@@ -773,25 +862,25 @@ err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rootfs_read_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat)
|
||||
|
||||
static int
|
||||
rootfs_read_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat)
|
||||
{
|
||||
struct rootfs_vnode *v = _v;
|
||||
struct rootfs_vnode *vnode = _v;
|
||||
|
||||
TRACE(("rootfs_rstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", v, v->id, stat));
|
||||
|
||||
//dprintf("rootfs_rstat\n");
|
||||
TRACE(("rootfs_rstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", vnode, vnode->id, stat));
|
||||
|
||||
// stream exists, but we know to return size 0, since we can only hold directories
|
||||
stat->st_ino = v->id;
|
||||
stat->st_ino = vnode->id;
|
||||
stat->st_size = 0;
|
||||
stat->st_mode = (S_IFDIR | DEFFILEMODE);
|
||||
stat->st_mode = vnode->stream.type | DEFFILEMODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rootfs_write_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask)
|
||||
rootfs_write_stat(fs_cookie _fs, fs_vnode _v, const struct stat *stat, int stat_mask)
|
||||
{
|
||||
#if ROOTFS_TRACE
|
||||
struct rootfs *fs = _fs;
|
||||
@@ -829,6 +918,8 @@ static struct fs_calls rootfs_calls = {
|
||||
&rootfs_ioctl,
|
||||
&rootfs_fsync,
|
||||
|
||||
&rootfs_read_link,
|
||||
&rootfs_symlink,
|
||||
&rootfs_unlink,
|
||||
&rootfs_rename,
|
||||
|
||||
|
||||
+258
-119
@@ -527,31 +527,42 @@ find_fs(const char *fs_name)
|
||||
static status_t
|
||||
entry_ref_to_vnode(fs_id fsID,vnode_id directoryID,const char *name,struct vnode **_vnode)
|
||||
{
|
||||
struct vnode *directory;
|
||||
struct vnode *directory, *vnode;
|
||||
vnode_id id;
|
||||
int status;
|
||||
int type;
|
||||
|
||||
status = get_vnode(fsID,directoryID,&directory,false);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
status = FS_CALL(directory,fs_lookup)(directory->mount->cookie,directory->private_node,name,&id);
|
||||
dec_vnode_ref_count(directory, false);
|
||||
status = FS_CALL(directory,fs_lookup)(directory->mount->cookie,
|
||||
directory->private_node, name, &id, &type);
|
||||
put_vnode(directory);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
return get_vnode(fsID,id,_vnode,false);
|
||||
mutex_lock(&vfs_vnode_mutex);
|
||||
vnode = lookup_vnode(fsID, id);
|
||||
mutex_unlock(&vfs_vnode_mutex);
|
||||
|
||||
if (vnode == NULL) {
|
||||
// fs_lookup() should have left the vnode referenced, so chances
|
||||
// are good that this will never happen
|
||||
panic("entry_ref_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", fsID, id);
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
*_vnode = vnode;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
|
||||
{
|
||||
char *nextPath;
|
||||
struct vnode *vnode;
|
||||
struct vnode *nextVnode;
|
||||
vnode_id vnid;
|
||||
int err = 0;
|
||||
|
||||
if (!path)
|
||||
@@ -573,6 +584,11 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct vnode *nextVnode;
|
||||
vnode_id vnodeID;
|
||||
char *nextPath;
|
||||
int type;
|
||||
|
||||
PRINT(("path_to_vnode: top of loop. p = %p, *p = %c, p = '%s'\n", path, *path, path));
|
||||
|
||||
// done?
|
||||
@@ -581,7 +597,8 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
|
||||
break;
|
||||
}
|
||||
|
||||
// walk to find the next component
|
||||
// walk to find the next path component ("path" will point to a single
|
||||
// path component), and filter out multiple slashes
|
||||
for (nextPath = path + 1;*nextPath != '\0' && *nextPath != '/';nextPath++);
|
||||
|
||||
if (*nextPath == '/') {
|
||||
@@ -602,30 +619,35 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
|
||||
}
|
||||
}
|
||||
|
||||
// tell the filesystem to parse this path
|
||||
err = FS_CALL(vnode,fs_lookup)(vnode->mount->cookie, vnode->private_node, path, &vnid);
|
||||
// tell the filesystem to get the vnode of this path component
|
||||
err = FS_CALL(vnode,fs_lookup)(vnode->mount->cookie, vnode->private_node, path, &vnodeID, &type);
|
||||
if (err < 0) {
|
||||
dec_vnode_ref_count(vnode, false);
|
||||
put_vnode(vnode);
|
||||
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);
|
||||
nextVnode = lookup_vnode(vnode->fs_id, vnid);
|
||||
mutex_unlock(&vfs_vnode_mutex);
|
||||
if (S_ISLNK(type)) {
|
||||
// ToDo: we have to resolve the link here
|
||||
nextVnode = NULL;
|
||||
} else {
|
||||
// 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);
|
||||
nextVnode = lookup_vnode(vnode->fs_id, vnodeID);
|
||||
mutex_unlock(&vfs_vnode_mutex);
|
||||
}
|
||||
|
||||
if (!nextVnode) {
|
||||
// pretty screwed up here
|
||||
panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", vnode->fs_id, vnid);
|
||||
panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", vnode->fs_id, vnodeID);
|
||||
err = ERR_VFS_PATH_NOT_FOUND;
|
||||
dec_vnode_ref_count(vnode, false);
|
||||
put_vnode(vnode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// decrease the ref count on the old dir we just looked up into
|
||||
dec_vnode_ref_count(vnode, false);
|
||||
put_vnode(vnode);
|
||||
|
||||
path = nextPath;
|
||||
vnode = nextVnode;
|
||||
@@ -634,7 +656,7 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
|
||||
if (vnode->covered_by) {
|
||||
nextVnode = vnode->covered_by;
|
||||
inc_vnode_ref_count(nextVnode);
|
||||
dec_vnode_ref_count(vnode, false);
|
||||
put_vnode(vnode);
|
||||
vnode = nextVnode;
|
||||
}
|
||||
}
|
||||
@@ -662,11 +684,12 @@ path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel
|
||||
strcpy(path, ".");
|
||||
} else {
|
||||
// replace the filename portion of the path with a '.'
|
||||
strcpy(filename, p+1);
|
||||
strcpy(filename, ++p);
|
||||
|
||||
if (p[1] != '\0'){
|
||||
p[1] = '.';
|
||||
p[2] = '\0';
|
||||
// ToDo: this could write behind the array limit
|
||||
if (p[0] != '\0'){
|
||||
p[0] = '.';
|
||||
p[1] = '\0';
|
||||
}
|
||||
}
|
||||
return path_to_vnode(path, _vnode, kernel);
|
||||
@@ -712,10 +735,24 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
||||
// 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;
|
||||
struct vnode *parentVnode;
|
||||
vnode_id parentID, id;
|
||||
int type;
|
||||
|
||||
// lookup the parent vnode
|
||||
status = FS_CALL(vnode,fs_lookup)(vnode->mount->cookie,vnode->private_node,"..",&parentId);
|
||||
status = FS_CALL(vnode,fs_lookup)(vnode->mount->cookie,vnode->private_node,"..",&parentID,&type);
|
||||
if (status < B_OK)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&vfs_vnode_mutex);
|
||||
parentVnode = lookup_vnode(vnode->fs_id, parentID);
|
||||
mutex_unlock(&vfs_vnode_mutex);
|
||||
|
||||
if (parentVnode == NULL) {
|
||||
panic("dir_vnode_to_path: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", vnode->fs_id, parentID);
|
||||
status = B_ENTRY_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Does the file system support getting the name of a vnode?
|
||||
// If so, get it here...
|
||||
@@ -728,27 +765,25 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
||||
|
||||
// release the current vnode, we only need its parent from now on
|
||||
put_vnode(vnode);
|
||||
vnode = parentVnode;
|
||||
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
goto out;
|
||||
|
||||
// ToDo: add an explicit check for loops in about 10 levels to do
|
||||
// real loop detection
|
||||
|
||||
// don't go deeper as 'maxLevel' to prevent circular loops
|
||||
if (maxLevel-- < 0)
|
||||
return ELOOP;
|
||||
|
||||
if (parentId == vnode->id) {
|
||||
// we have reached the root level directory of this file system
|
||||
break;
|
||||
if (maxLevel-- < 0) {
|
||||
status = ELOOP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (parentID == id) {
|
||||
// we have reached the root level directory of this file system
|
||||
// which means we have constructed the full path
|
||||
break;
|
||||
}
|
||||
|
||||
if (!FS_CALL(vnode,fs_get_vnode_name)) {
|
||||
// If we don't got the vnode's name yet, we have to search for it
|
||||
@@ -771,10 +806,8 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
||||
FS_CALL(vnode,fs_close_dir)(vnode->mount->cookie,vnode->private_node,cookie);
|
||||
}
|
||||
|
||||
if (status < B_OK) {
|
||||
put_vnode(vnode);
|
||||
return status;
|
||||
}
|
||||
if (status < B_OK)
|
||||
goto out;
|
||||
}
|
||||
|
||||
// add the name infront of the current path
|
||||
@@ -782,8 +815,8 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
||||
length = strlen(name);
|
||||
insert -= length;
|
||||
if (insert <= 0) {
|
||||
put_vnode(vnode);
|
||||
return ENOBUFS;
|
||||
status = ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
memcpy(path + insert, name, length);
|
||||
path[--insert] = '/';
|
||||
@@ -791,13 +824,54 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
||||
|
||||
// add the mountpoint
|
||||
length = strlen(vnode->mount->mount_point);
|
||||
if (bufferSize - (sizeof(path) - insert) < length + 1)
|
||||
return ENOBUFS;
|
||||
if (bufferSize - (sizeof(path) - insert) < length + 1) {
|
||||
status = ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(buffer, vnode->mount->mount_point, length);
|
||||
if (insert != sizeof(path))
|
||||
memcpy(buffer + length, path + insert, sizeof(path) - insert);
|
||||
|
||||
out:
|
||||
put_vnode(vnode);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
check_path(char *to)
|
||||
{
|
||||
int32 length = 0;
|
||||
|
||||
// check length of every path component
|
||||
|
||||
while (*to) {
|
||||
char *begin;
|
||||
if (*to == '/')
|
||||
to++, length++;
|
||||
|
||||
begin = to;
|
||||
while (*to != '/' && *to)
|
||||
to++, length++;
|
||||
|
||||
if (to - begin > B_FILE_NAME_LENGTH)
|
||||
return B_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
// complete path if there is a slash at the end
|
||||
|
||||
if (*(to - 1) == '/') {
|
||||
if (length > SYS_MAX_PATH_LEN - 2)
|
||||
return B_NAME_TOO_LONG;
|
||||
|
||||
to[0] = '.';
|
||||
to[1] = '\0';
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -810,14 +884,13 @@ int
|
||||
vfs_get_vnode(fs_id fsID, vnode_id vnodeID, fs_vnode *_fsNode)
|
||||
{
|
||||
struct vnode *vnode;
|
||||
int err;
|
||||
|
||||
err = get_vnode(fsID, vnodeID, &vnode, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
int status = get_vnode(fsID, vnodeID, &vnode, true);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
*_fsNode = vnode->private_node;
|
||||
return B_NO_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -833,7 +906,7 @@ vfs_put_vnode(fs_id fsID, vnode_id vnodeID)
|
||||
if (vnode)
|
||||
dec_vnode_ref_count(vnode, true);
|
||||
|
||||
return B_NO_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1868,6 +1941,29 @@ common_sync(int fd, bool kernel)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
common_symlink(char *path, const char *toPath, bool kernel)
|
||||
{
|
||||
// path validity checks have to be in the calling function!
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
struct vnode *vnode;
|
||||
int status;
|
||||
|
||||
status = path_to_dir_vnode(path, &vnode, name, kernel);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (FS_CALL(vnode,fs_symlink) != NULL)
|
||||
status = FS_CALL(vnode,fs_symlink)(vnode->mount->cookie, vnode->private_node, name, toPath);
|
||||
else
|
||||
status = EROFS;
|
||||
|
||||
put_vnode(vnode);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
common_unlink(char *path, bool kernel)
|
||||
{
|
||||
@@ -1928,19 +2024,19 @@ err:
|
||||
|
||||
|
||||
static int
|
||||
common_write_stat(char *path, struct stat *stat, int stat_mask, bool kernel)
|
||||
common_write_stat(char *path, const struct stat *stat, int statMask, bool kernel)
|
||||
{
|
||||
struct vnode *vnode;
|
||||
int status;
|
||||
|
||||
FUNCTION(("vfs_write_stat: path '%s', stat 0x%p, stat_mask %d, kernel %d\n", path, stat, stat_mask, kernel));
|
||||
FUNCTION(("vfs_write_stat: path '%s', stat 0x%p, stat_mask %d, kernel %d\n", path, stat, statMask, kernel));
|
||||
|
||||
status = path_to_vnode(path, &vnode, kernel);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (FS_CALL(vnode,fs_write_stat))
|
||||
status = FS_CALL(vnode,fs_write_stat)(vnode->mount->cookie, vnode->private_node, stat, stat_mask);
|
||||
status = FS_CALL(vnode,fs_write_stat)(vnode->mount->cookie, vnode->private_node, stat, statMask);
|
||||
else
|
||||
status = EROFS;
|
||||
|
||||
@@ -2070,29 +2166,27 @@ err:
|
||||
static int
|
||||
fs_unmount(char *path, bool kernel)
|
||||
{
|
||||
struct vnode *v;
|
||||
struct fs_mount *mount;
|
||||
struct vnode *vnode;
|
||||
int err;
|
||||
|
||||
FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel));
|
||||
|
||||
err = path_to_vnode(path, &v, kernel);
|
||||
if (err < 0) {
|
||||
err = ERR_VFS_PATH_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
err = path_to_vnode(path, &vnode, kernel);
|
||||
if (err < 0)
|
||||
return ERR_VFS_PATH_NOT_FOUND;
|
||||
|
||||
mutex_lock(&vfs_mount_op_mutex);
|
||||
|
||||
mount = find_mount(v->fs_id);
|
||||
mount = find_mount(vnode->fs_id);
|
||||
if (!mount)
|
||||
panic("vfs_unmount: fsid_to_mount failed on root vnode @%p of mount\n", v);
|
||||
panic("vfs_unmount: fsid_to_mount failed on root vnode @%p of mount\n", vnode);
|
||||
|
||||
if (mount->root_vnode != v) {
|
||||
if (mount->root_vnode != vnode) {
|
||||
// not mountpoint
|
||||
dec_vnode_ref_count(v, false);
|
||||
dec_vnode_ref_count(vnode, false);
|
||||
err = ERR_VFS_NOT_MOUNTPOINT;
|
||||
goto err1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* grab the vnode master mutex to keep someone from creating a vnode
|
||||
@@ -2102,24 +2196,24 @@ fs_unmount(char *path, bool kernel)
|
||||
/* 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) {
|
||||
// cycle through the list of vnodes associated with this mount and
|
||||
// make sure all of them are not busy or have refs on them
|
||||
for (vnode = mount->vnodes_head; vnode != NULL; vnode = vnode->mount_next) {
|
||||
if (vnode->busy || vnode->ref_count != 0) {
|
||||
mount->root_vnode->ref_count += 2;
|
||||
mutex_unlock(&vfs_vnode_mutex);
|
||||
dec_vnode_ref_count(mount->root_vnode, false);
|
||||
|
||||
err = EBUSY;
|
||||
goto err1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
for (vnode = mount->vnodes_head; vnode; vnode = vnode->mount_next)
|
||||
if (vnode != mount->root_vnode)
|
||||
vnode->busy = true;
|
||||
mount->unmounting = true;
|
||||
|
||||
mutex_unlock(&vfs_vnode_mutex);
|
||||
@@ -2148,9 +2242,8 @@ fs_unmount(char *path, bool kernel)
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
mutex_unlock(&vfs_mount_op_mutex);
|
||||
err:
|
||||
mutex_unlock(&vfs_mount_op_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2210,7 +2303,7 @@ error:
|
||||
|
||||
|
||||
static int
|
||||
fs_write_info(dev_t device, struct fs_info *info, int mask)
|
||||
fs_write_info(dev_t device, const struct fs_info *info, int mask)
|
||||
{
|
||||
struct fs_mount *mount;
|
||||
int status;
|
||||
@@ -2264,7 +2357,7 @@ set_cwd(char *path, bool kernel)
|
||||
struct stat stat;
|
||||
int rc;
|
||||
|
||||
FUNCTION(("vfs_set_cwd: path=\'%s\'\n", path));
|
||||
FUNCTION(("vfs_set_cwd: path = \'%s\'\n", path));
|
||||
|
||||
// Get vnode for passed path, and bail if it failed
|
||||
rc = path_to_vnode(path, &vnode, kernel);
|
||||
@@ -2309,7 +2402,7 @@ err:
|
||||
int
|
||||
sys_mount(const char *path, const char *device, const char *fs_name, void *args)
|
||||
{
|
||||
char buf[SYS_MAX_PATH_LEN+1];
|
||||
char buf[SYS_MAX_PATH_LEN + 1];
|
||||
|
||||
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
||||
buf[SYS_MAX_PATH_LEN] = 0;
|
||||
@@ -2321,7 +2414,7 @@ sys_mount(const char *path, const char *device, const char *fs_name, void *args)
|
||||
int
|
||||
sys_unmount(const char *path)
|
||||
{
|
||||
char buf[SYS_MAX_PATH_LEN+1];
|
||||
char buf[SYS_MAX_PATH_LEN + 1];
|
||||
|
||||
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
||||
buf[SYS_MAX_PATH_LEN] = 0;
|
||||
@@ -2415,7 +2508,7 @@ sys_create_entry_ref(dev_t device, ino_t inode, const char *name, int omode, int
|
||||
int
|
||||
sys_create(const char *path, int omode, int perms)
|
||||
{
|
||||
char buffer[SYS_MAX_PATH_LEN+1];
|
||||
char buffer[SYS_MAX_PATH_LEN + 1];
|
||||
|
||||
strncpy(buffer, path, SYS_MAX_PATH_LEN);
|
||||
buffer[SYS_MAX_PATH_LEN] = '\0';
|
||||
@@ -2439,7 +2532,7 @@ sys_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms)
|
||||
int
|
||||
sys_create_dir(const char *path, int perms)
|
||||
{
|
||||
char buffer[SYS_MAX_PATH_LEN+1];
|
||||
char buffer[SYS_MAX_PATH_LEN + 1];
|
||||
|
||||
strncpy(buffer, path, SYS_MAX_PATH_LEN);
|
||||
buffer[SYS_MAX_PATH_LEN] = 0;
|
||||
@@ -2448,10 +2541,31 @@ sys_create_dir(const char *path, int perms)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sys_symlink(const char *userPath, const char *userToPath)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
char toPath[SYS_MAX_PATH_LEN + 1];
|
||||
int status;
|
||||
|
||||
strncpy(path, userPath, SYS_MAX_PATH_LEN);
|
||||
path[SYS_MAX_PATH_LEN] = '\0';
|
||||
|
||||
strncpy(toPath, userToPath, SYS_MAX_PATH_LEN);
|
||||
toPath[SYS_MAX_PATH_LEN] = '\0';
|
||||
|
||||
status = check_path(toPath);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return common_symlink(path, toPath, true);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sys_unlink(const char *path)
|
||||
{
|
||||
char buf[SYS_MAX_PATH_LEN+1];
|
||||
char buf[SYS_MAX_PATH_LEN + 1];
|
||||
|
||||
strncpy(buf, path, SYS_MAX_PATH_LEN);
|
||||
buf[SYS_MAX_PATH_LEN] = 0;
|
||||
@@ -2463,8 +2577,8 @@ sys_unlink(const char *path)
|
||||
int
|
||||
sys_rename(const char *oldpath, const char *newpath)
|
||||
{
|
||||
char buf1[SYS_MAX_PATH_LEN+1];
|
||||
char buf2[SYS_MAX_PATH_LEN+1];
|
||||
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;
|
||||
@@ -2554,20 +2668,16 @@ sys_setcwd(const char *_path)
|
||||
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];
|
||||
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)
|
||||
if (!CHECK_USER_ADDRESS(upath)
|
||||
|| !CHECK_USER_ADDRESS(ufs_name)
|
||||
|| !CHECK_USER_ADDRESS(udevice))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
if ((addr)ufs_name >= KERNEL_BASE && (addr)ufs_name <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
if (udevice != NULL && (addr)udevice >= KERNEL_BASE && (addr)udevice <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
@@ -2593,7 +2703,7 @@ user_mount(const char *upath, const char *udevice, const char *ufs_name, void *a
|
||||
int
|
||||
user_unmount(const char *upath)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN+1];
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
int rc;
|
||||
|
||||
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
||||
@@ -2633,16 +2743,16 @@ user_open_entry_ref(dev_t device, ino_t inode, const char *uname, int omode)
|
||||
int
|
||||
user_open(const char *upath, int omode)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN];
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
int rc;
|
||||
|
||||
if (!CHECK_USER_ADDRESS(upath))
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc = user_strncpy(path, upath, sizeof(path) - 1);
|
||||
rc = user_strncpy(path, upath, sizeof(path));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
path[sizeof(path) - 1] = 0;
|
||||
path[sizeof(path)] = 0;
|
||||
|
||||
return file_open(path, omode, false);
|
||||
}
|
||||
@@ -2676,16 +2786,16 @@ user_open_dir_entry_ref(dev_t device, ino_t inode, const char *uname)
|
||||
int
|
||||
user_open_dir(const char *upath)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN];
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
int status;
|
||||
|
||||
if (!CHECK_USER_ADDRESS(upath))
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
status = user_strncpy(path, upath, sizeof(path) - 1);
|
||||
status = user_strncpy(path, upath, sizeof(path));
|
||||
if (status < 0)
|
||||
return status;
|
||||
path[sizeof(path) - 1] = 0;
|
||||
path[sizeof(path)] = 0;
|
||||
|
||||
return dir_open(path, false);
|
||||
}
|
||||
@@ -2719,16 +2829,16 @@ user_create_entry_ref(dev_t device, ino_t inode, const char *uname, int omode, i
|
||||
int
|
||||
user_create(const char *upath, int omode, int perms)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN];
|
||||
int rc;
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
int status;
|
||||
|
||||
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';
|
||||
status = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
||||
if (status < 0)
|
||||
return status;
|
||||
path[SYS_MAX_PATH_LEN] = '\0';
|
||||
|
||||
return file_create(path, omode, perms, false);
|
||||
}
|
||||
@@ -2755,25 +2865,54 @@ user_create_dir_entry_ref(dev_t device, ino_t inode, const char *uname, int perm
|
||||
int
|
||||
user_create_dir(const char *upath, int perms)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN];
|
||||
int rc;
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
int status;
|
||||
|
||||
if (!CHECK_USER_ADDRESS(upath))
|
||||
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';
|
||||
status = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
|
||||
if (status < 0)
|
||||
return status;
|
||||
path[SYS_MAX_PATH_LEN] = '\0';
|
||||
|
||||
return dir_create(path, perms, false);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
user_symlink(const char *userPath, const char *userToPath)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
char toPath[SYS_MAX_PATH_LEN + 1];
|
||||
int status;
|
||||
|
||||
if (!CHECK_USER_ADDRESS(userPath)
|
||||
|| !CHECK_USER_ADDRESS(userToPath))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
status = user_strncpy(path, userPath, SYS_MAX_PATH_LEN);
|
||||
if (status < 0)
|
||||
return status;
|
||||
path[SYS_MAX_PATH_LEN] = '\0';
|
||||
|
||||
status = user_strncpy(toPath, userToPath, SYS_MAX_PATH_LEN);
|
||||
if (status < 0)
|
||||
return status;
|
||||
toPath[SYS_MAX_PATH_LEN] = '\0';
|
||||
|
||||
status = check_path(toPath);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return common_symlink(path, toPath, false);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
user_unlink(const char *upath)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN+1];
|
||||
char path[SYS_MAX_PATH_LEN + 1];
|
||||
int rc;
|
||||
|
||||
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
||||
@@ -2791,8 +2930,8 @@ user_unlink(const char *upath)
|
||||
int
|
||||
user_rename(const char *uoldpath, const char *unewpath)
|
||||
{
|
||||
char oldpath[SYS_MAX_PATH_LEN+1];
|
||||
char newpath[SYS_MAX_PATH_LEN+1];
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user