diff --git a/src/kernel/core/fs/bootfs.c b/src/kernel/core/fs/bootfs.c index f867fd20d6..077e691663 100755 --- a/src/kernel/core/fs/bootfs.c +++ b/src/kernel/core/fs/bootfs.c @@ -381,7 +381,7 @@ bootfs_create_vnode_tree(struct bootfs *fs, struct bootfs_vnode *root) static int -bootfs_mount(fs_cookie *_fs, fs_id id, const char *device, void *args, vnode_id *root_vnid) +bootfs_mount(fs_id id, const char *device, void *args, fs_cookie *_fs, vnode_id *root_vnid) { struct bootfs *fs; struct bootfs_vnode *v; @@ -535,12 +535,12 @@ bootfs_get_vnode_name(fs_cookie _fs, fs_vnode _vnode, char *buffer, size_t buffe static int -bootfs_getvnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r) +bootfs_get_vnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r) { struct bootfs *fs = (struct bootfs *)_fs; int err; - TRACE(("bootfs_getvnode: asking for vnode 0x%x 0x%x, r %d\n", id, r)); + TRACE(("bootfs_get_vnode: asking for vnode 0x%x 0x%x, r %d\n", id, r)); if(!r) mutex_lock(&fs->lock); @@ -550,7 +550,7 @@ bootfs_getvnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r) if(!r) mutex_unlock(&fs->lock); - TRACE(("bootfs_getnvnode: looked it up at 0x%x\n", *v)); + TRACE(("bootfs_get_vnode: looked it up at 0x%x\n", *v)); if(*v) return 0; @@ -560,32 +560,32 @@ bootfs_getvnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r) static int -bootfs_putvnode(fs_cookie _fs, fs_vnode _v, bool r) +bootfs_put_vnode(fs_cookie _fs, fs_vnode _v, bool r) { struct bootfs_vnode *v = (struct bootfs_vnode *)_v; - TRACE(("bootfs_putvnode: entry on vnode 0x%x 0x%x, r %d\n", v->id, r)); + TRACE(("bootfs_put_vnode: entry on vnode 0x%x 0x%x, r %d\n", v->id, r)); return 0; // whatever } static int -bootfs_removevnode(fs_cookie _fs, fs_vnode _v, bool r) +bootfs_remove_vnode(fs_cookie _fs, fs_vnode _v, bool reenter) { struct bootfs *fs = (struct bootfs *)_fs; struct bootfs_vnode *v = (struct bootfs_vnode *)_v; struct bootfs_vnode dummy; int err; - TRACE(("bootfs_removevnode: remove 0x%x (0x%x 0x%x), r %d\n", v, v->id, r)); + TRACE(("bootfs_remove_vnode: remove 0x%x (0x%x 0x%x), r %d\n", v, v->id, r)); - if(!r) + if (!reenter) mutex_lock(&fs->lock); - if(v->dir_next) { + if (v->dir_next) { // can't remove node if it's linked to the dir - panic("bootfs_removevnode: vnode %p asked to be removed is present in dir\n", v); + panic("bootfs_remove_vnode: vnode %p asked to be removed is present in dir\n", v); } bootfs_delete_vnode(fs, v, false); @@ -593,7 +593,7 @@ bootfs_removevnode(fs_cookie _fs, fs_vnode _v, bool r) err = 0; err: - if (!r) + if (!reenter) mutex_unlock(&fs->lock); return err; @@ -601,14 +601,14 @@ err: static int -bootfs_create(fs_cookie _fs, fs_vnode _dir, file_cookie *_cookie, vnode_id *new_vnid, const char *name, int omode, int perms) +bootfs_create(fs_cookie _fs, fs_vnode _dir, const char *name, int omode, int perms, file_cookie *_cookie, vnode_id *new_vnid) { return EROFS; } static int -bootfs_open(fs_cookie _fs, fs_vnode _v, file_cookie *_cookie, int oflags) +bootfs_open(fs_cookie _fs, fs_vnode _v, int oflags, file_cookie *_cookie) { struct bootfs *fs = _fs; struct bootfs_vnode *vnode = _v; @@ -879,7 +879,7 @@ bootfs_ioctl(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, ulong op, void *bu static int -bootfs_canpage(fs_cookie _fs, fs_vnode _v) +bootfs_can_page(fs_cookie _fs, fs_vnode _v) { struct bootfs_vnode *v = _v; @@ -893,7 +893,7 @@ bootfs_canpage(fs_cookie _fs, fs_vnode _v) static ssize_t -bootfs_readpage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +bootfs_read_page(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) { struct bootfs *fs = _fs; struct bootfs_vnode *v = _v; @@ -912,7 +912,7 @@ bootfs_readpage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) memcpy(vecs->vec[i].iov_base, v->stream.u.file.start + pos, copy_len); - if(copy_len < vecs->vec[i].iov_len) + if (copy_len < vecs->vec[i].iov_len) memset((char *)vecs->vec[i].iov_base + copy_len, 0, vecs->vec[i].iov_len - copy_len); pos += vecs->vec[i].iov_len; @@ -924,7 +924,7 @@ bootfs_readpage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) static ssize_t -bootfs_writepage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +bootfs_write_page(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) { struct bootfs *fs = _fs; struct bootfs_vnode *v = _v; @@ -1007,18 +1007,20 @@ bootfs_write_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask) static struct fs_calls bootfs_calls = { &bootfs_mount, &bootfs_unmount, + NULL, + NULL, &bootfs_sync, &bootfs_lookup, &bootfs_get_vnode_name, - &bootfs_getvnode, - &bootfs_putvnode, - &bootfs_removevnode, + &bootfs_get_vnode, + &bootfs_put_vnode, + &bootfs_remove_vnode, - &bootfs_canpage, - &bootfs_readpage, - &bootfs_writepage, + &bootfs_can_page, + &bootfs_read_page, + &bootfs_write_page, /* common */ &bootfs_ioctl, diff --git a/src/kernel/core/fs/devfs.c b/src/kernel/core/fs/devfs.c index bd7f9fb974..fd11736c69 100755 --- a/src/kernel/core/fs/devfs.c +++ b/src/kernel/core/fs/devfs.c @@ -396,7 +396,7 @@ err2: static int -devfs_mount(fs_cookie *_fs, fs_id id, const char *devfs, void *args, vnode_id *root_vnid) +devfs_mount(fs_id id, const char *devfs, void *args, fs_cookie *_fs, vnode_id *root_vnid) { struct devfs *fs; struct devfs_vnode *v; @@ -612,14 +612,14 @@ devfs_remove_vnode(fs_cookie _fs, fs_vnode _v, bool reenter) static int -devfs_create(fs_cookie _fs, fs_vnode _dir, file_cookie *_cookie, vnode_id *new_vnid, const char *name, int omode, int perms) +devfs_create(fs_cookie _fs, fs_vnode _dir, const char *name, int omode, int perms, file_cookie *_cookie, vnode_id *new_vnid) { return EROFS; } static int -devfs_open(fs_cookie _fs, fs_vnode _v, file_cookie *_cookie, int oflags) +devfs_open(fs_cookie _fs, fs_vnode _v, int oflags, file_cookie *_cookie) { struct devfs *fs = _fs; struct devfs_vnode *vnode = _v; @@ -1043,6 +1043,8 @@ devfs_write_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask) static struct fs_calls devfs_calls = { &devfs_mount, &devfs_unmount, + NULL, + NULL, &devfs_sync, &devfs_lookup, diff --git a/src/kernel/core/fs/rootfs.c b/src/kernel/core/fs/rootfs.c index 1e9e0fec60..915cf2417f 100755 --- a/src/kernel/core/fs/rootfs.c +++ b/src/kernel/core/fs/rootfs.c @@ -212,7 +212,7 @@ rootfs_is_dir_empty(struct rootfs_vnode *dir) static int -rootfs_mount(fs_cookie *_fs, fs_id id, const char *device, void *args, vnode_id *root_vnid) +rootfs_mount(fs_id id, const char *device, void *args, fs_cookie *_fs, vnode_id *root_vnid) { struct rootfs *fs; struct rootfs_vnode *v; @@ -425,14 +425,14 @@ rootfs_remove_vnode(fs_cookie _fs, fs_vnode _v, bool r) static int -rootfs_create(fs_cookie _fs, fs_vnode _dir, file_cookie *_cookie, vnode_id *new_vnid, const char *name, int omode, int perms) +rootfs_create(fs_cookie _fs, fs_vnode _dir, const char *name, int omode, int perms, file_cookie *_cookie, vnode_id *new_vnid) { return EINVAL; } static int -rootfs_open(fs_cookie _fs, fs_vnode _v, file_cookie *_cookie, int oflags) +rootfs_open(fs_cookie _fs, fs_vnode _v, int oflags, file_cookie *_cookie) { // allow to open the file, but it can't be done anything with it return B_OK; @@ -810,6 +810,8 @@ rootfs_write_stat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask) static struct fs_calls rootfs_calls = { &rootfs_mount, &rootfs_unmount, + NULL, + NULL, &rootfs_sync, &rootfs_lookup, diff --git a/src/kernel/core/fs/vfs.c b/src/kernel/core/fs/vfs.c index 8c03ff9a9d..929610332b 100755 --- a/src/kernel/core/fs/vfs.c +++ b/src/kernel/core/fs/vfs.c @@ -51,6 +51,11 @@ #ifndef B_FILE_NAME_LENGTH # define B_FILE_NAME_LENGTH 256 #endif +#include + +// Passed in buffers from user-space shouldn't be in the kernel +#define CHECK_USER_ADDRESS(x) \ + ((addr)(x) < KERNEL_BASE || (addr)(x) > KERNEL_TOP) struct vnode { struct vnode *next; @@ -673,12 +678,15 @@ path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel * 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 + * To protect against 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. + * + * It might be a good idea, though, to check if the returned path exists + * in the calling function (it's not done here because of efficiency) */ static status_t @@ -724,6 +732,9 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize) if (status < B_OK) return status; + // 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; @@ -1443,7 +1454,7 @@ create_vnode(struct vnode *directory, const char *name, int omode, int perms, bo if (FS_CALL(directory,fs_create) == NULL) return EROFS; - status = FS_CALL(directory,fs_create)(directory->mount->cookie, directory->private_node, &cookie, &newID, name, omode, perms); + status = FS_CALL(directory,fs_create)(directory->mount->cookie, directory->private_node, name, omode, perms, &cookie, &newID); if (status < B_OK) return status; @@ -1479,7 +1490,7 @@ open_vnode(struct vnode *vnode, int omode, bool kernel) file_cookie cookie; int status; - status = FS_CALL(vnode,fs_open)(vnode->mount->cookie, vnode->private_node, &cookie, omode); + status = FS_CALL(vnode,fs_open)(vnode->mount->cookie, vnode->private_node, omode, &cookie); if (status < 0) return status; @@ -1665,12 +1676,35 @@ file_seek(struct file_descriptor *descriptor, off_t pos, int seekType) } +static int +dir_create_entry_ref(fs_id fsID, vnode_id parentID, const char *name, int perms, bool kernel) +{ + struct vnode *vnode; + vnode_id newID; + int status; + + FUNCTION(("dir_create_entry_ref(dev = %ld, ino = %Ld, name = '%s', perms = %d)\n", fdID, parentID, name, perms)); + + status = get_vnode(fsID, parentID, &vnode, kernel); + if (status < B_OK) + return status; + + if (FS_CALL(vnode, fs_create_dir)) + status = FS_CALL(vnode, fs_create_dir)(vnode->mount->cookie, vnode->private_node, name, perms, &newID); + else + status = EROFS; + + put_vnode(vnode); + return status; +} + + static int dir_create(char *path, int perms, bool kernel) { char filename[SYS_MAX_NAME_LEN]; struct vnode *vnode; - vnode_id vnid; + vnode_id newID; int status; FUNCTION(("dir_create: path '%s', perms %d, kernel %d\n", path, perms, kernel)); @@ -1680,7 +1714,7 @@ dir_create(char *path, int perms, bool kernel) return status; if (FS_CALL(vnode,fs_create_dir)) - status = FS_CALL(vnode,fs_create_dir)(vnode->mount->cookie, vnode->private_node, filename, perms, &vnid); + status = FS_CALL(vnode,fs_create_dir)(vnode->mount->cookie, vnode->private_node, filename, perms, &newID); else status = EROFS; @@ -1961,7 +1995,7 @@ fs_mount(char *path, const char *device, const char *fs_name, void *args, bool k goto err3; } - err = mount->fs->calls->fs_mount(&mount->cookie, mount->id, device, NULL, &root_id); + err = mount->fs->calls->fs_mount(mount->id, device, NULL, &mount->cookie, &root_id); if (err < 0) { err = ERR_VFS_GENERAL; goto err3; @@ -1988,7 +2022,7 @@ fs_mount(char *path, const char *device, const char *fs_name, void *args, bool k mount->covers_vnode = covered_vnode; // mount it - err = mount->fs->calls->fs_mount(&mount->cookie, mount->id, device, NULL, &root_id); + err = mount->fs->calls->fs_mount(mount->id, device, NULL, &mount->cookie, &root_id); if (err < 0) goto err4; } @@ -2146,6 +2180,60 @@ fs_sync(void) } +static int +fs_read_info(dev_t device, struct fs_info *info) +{ + struct fs_mount *mount; + int status; + + mutex_lock(&vfs_mount_mutex); + + mount = find_mount(device); + if (mount == NULL) { + status = EINVAL; + goto error; + } + + if (mount->fs->calls->fs_read_fs_info) + status = mount->fs->calls->fs_read_fs_info(mount->cookie, info); + else + status = EOPNOTSUPP; + + // fill in other info the file system doesn't know about + info->dev = mount->id; + info->root = mount->root_vnode->id; + +error: + mutex_unlock(&vfs_mount_mutex); + return status; +} + + +static int +fs_write_info(dev_t device, struct fs_info *info, int mask) +{ + struct fs_mount *mount; + int status; + + mutex_lock(&vfs_mount_mutex); + + mount = find_mount(device); + if (mount == NULL) { + status = EINVAL; + goto error; + } + + if (mount->fs->calls->fs_write_fs_info) + status = mount->fs->calls->fs_write_fs_info(mount->cookie, info, mask); + else + status = EROFS; + +error: + mutex_unlock(&vfs_mount_mutex); + return status; +} + + static int get_cwd(char *buffer, size_t size, bool kernel) { @@ -2249,22 +2337,53 @@ sys_sync(void) } +int +sys_open_entry_ref(dev_t device, ino_t inode, const char *name, int omode) +{ + char nameCopy[B_FILE_NAME_LENGTH]; + + strncpy(nameCopy, name, sizeof(nameCopy) - 1); + nameCopy[sizeof(nameCopy) - 1] = '\0'; + + return file_open_entry_ref(device, inode, nameCopy, omode, true); +} + + int sys_open(const char *path, int omode) { - char buffer[SYS_MAX_PATH_LEN+1]; + char pathCopy[SYS_MAX_PATH_LEN + 1]; - strncpy(buffer, path, SYS_MAX_PATH_LEN); - buffer[SYS_MAX_PATH_LEN] = 0; + strncpy(pathCopy, path, SYS_MAX_PATH_LEN); + pathCopy[SYS_MAX_PATH_LEN] = 0; - return file_open(buffer, omode, true); + return file_open(pathCopy, omode, true); +} + + +int +sys_open_dir_node_ref(dev_t device, ino_t inode) +{ + return dir_open_node_ref(device, inode, true); +} + + +int +sys_open_dir_entry_ref(dev_t device, ino_t inode, const char *name) +{ + char nameCopy[B_FILE_NAME_LENGTH]; + + strncpy(nameCopy, name, sizeof(nameCopy) - 1); + nameCopy[sizeof(nameCopy) - 1] = '\0'; + + return dir_open_entry_ref(device, inode, nameCopy, true); } int sys_open_dir(const char *path) { - 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; @@ -2280,18 +2399,43 @@ sys_fsync(int fd) } +int +sys_create_entry_ref(dev_t device, ino_t inode, const char *name, int omode, int perms) +{ + char nameCopy[B_FILE_NAME_LENGTH]; + int status; + + strncpy(nameCopy, name, sizeof(nameCopy) - 1); + nameCopy[sizeof(nameCopy) - 1] = '\0'; + + return file_create_entry_ref(device, inode, nameCopy, omode, perms, true); +} + + int sys_create(const char *path, int omode, int perms) { char buffer[SYS_MAX_PATH_LEN+1]; strncpy(buffer, path, SYS_MAX_PATH_LEN); - buffer[SYS_MAX_PATH_LEN] = 0; + buffer[SYS_MAX_PATH_LEN] = '\0'; return file_create(buffer, omode, perms, true); } +int +sys_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms) +{ + char nameCopy[B_FILE_NAME_LENGTH]; + + strncpy(nameCopy, name, sizeof(nameCopy) - 1); + nameCopy[sizeof(nameCopy) - 1] = '\0'; + + return dir_create_entry_ref(device, inode, nameCopy, perms, true); +} + + int sys_create_dir(const char *path, int perms) { @@ -2416,7 +2560,7 @@ user_mount(const char *upath, const char *udevice, const char *ufs_name, void *a int rc; if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) - return ERR_VM_BAD_USER_MEMORY; + return B_BAD_ADDRESS; if ((addr)ufs_name >= KERNEL_BASE && (addr)ufs_name <= KERNEL_TOP) return ERR_VM_BAD_USER_MEMORY; @@ -2468,37 +2612,80 @@ user_sync(void) } +int +user_open_entry_ref(dev_t device, ino_t inode, const char *uname, int omode) +{ + char name[B_FILE_NAME_LENGTH]; + int status; + + if (!CHECK_USER_ADDRESS(uname)) + return ERR_VM_BAD_USER_MEMORY; + + status = user_strncpy(name, uname, sizeof(name) - 1); + if (status < B_OK) + return status; + name[sizeof(name) - 1] = '\0'; + + return file_open_entry_ref(device, inode, name, omode, false); +} + + int user_open(const char *upath, int omode) { char path[SYS_MAX_PATH_LEN]; int rc; - if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + if (!CHECK_USER_ADDRESS(upath)) return ERR_VM_BAD_USER_MEMORY; - rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + rc = user_strncpy(path, upath, sizeof(path) - 1); if (rc < 0) return rc; - path[SYS_MAX_PATH_LEN-1] = 0; + path[sizeof(path) - 1] = 0; return file_open(path, omode, false); } +int +user_open_dir_node_ref(dev_t device, ino_t inode) +{ + return dir_open_node_ref(device, inode, false); +} + + +int +user_open_dir_entry_ref(dev_t device, ino_t inode, const char *uname) +{ + char name[B_FILE_NAME_LENGTH]; + int status; + + if (!CHECK_USER_ADDRESS(uname)) + return ERR_VM_BAD_USER_MEMORY; + + status = user_strncpy(name, uname, sizeof(name) - 1); + if (status < B_OK) + return status; + name[sizeof(name) - 1] = '\0'; + + return dir_open_entry_ref(device, inode, name, false); +} + + int user_open_dir(const char *upath) { char path[SYS_MAX_PATH_LEN]; - int rc; + int status; - if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + 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, sizeof(path) - 1); + if (status < 0) + return status; + path[sizeof(path) - 1] = 0; return dir_open(path, false); } @@ -2511,6 +2698,24 @@ user_fsync(int fd) } +int +user_create_entry_ref(dev_t device, ino_t inode, const char *uname, int omode, int perms) +{ + char name[B_FILE_NAME_LENGTH]; + int status; + + if (!CHECK_USER_ADDRESS(uname)) + return ERR_VM_BAD_USER_MEMORY; + + status = user_strncpy(name, uname, sizeof(name) - 1); + if (status < 0) + return status; + name[sizeof(name) - 1] = '\0'; + + return file_create_entry_ref(device, inode, name, omode, perms, false); +} + + int user_create(const char *upath, int omode, int perms) { @@ -2523,25 +2728,43 @@ user_create(const char *upath, int omode, int perms) rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN - 1); if (rc < 0) return rc; - path[SYS_MAX_PATH_LEN - 1] = 0; + path[SYS_MAX_PATH_LEN - 1] = '\0'; return file_create(path, omode, perms, false); } +int +user_create_dir_entry_ref(dev_t device, ino_t inode, const char *uname, int perms) +{ + char name[B_FILE_NAME_LENGTH]; + int status; + + if (!CHECK_USER_ADDRESS(uname)) + return ERR_VM_BAD_USER_MEMORY; + + status = user_strncpy(name, uname, sizeof(name) - 1); + if (status < 0) + return status; + name[sizeof(name) - 1] = '\0'; + + return dir_create_entry_ref(device, inode, name, perms, false); +} + + int user_create_dir(const char *upath, int perms) { char path[SYS_MAX_PATH_LEN]; int rc; - if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + 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; + path[SYS_MAX_PATH_LEN - 1] = '\0'; return dir_create(path, perms, false); }