refactor: eliminate edge case when try to access parent of root.
chore: minor refactoring, clean-up and small fixes.
__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
mount,
const char*,
source,
const char*,
target,
const char*,
mount,
const char*,
source,
const char*,
target,
const char*,
+ fstype,
+ int,
+ options)
__LXSYSCALL1(int, unmount, const char*, target)
__LXSYSCALL1(int, unmount, const char*, target)
#define FSEEK_CUR 0x2
#define FSEEK_END 0x3
#define FSEEK_CUR 0x2
#define FSEEK_END 0x3
#endif /* __LUNAIX_FOPTIONS_H */
#endif /* __LUNAIX_FOPTIONS_H */
int (*write)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
int (*read)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
int (*readdir)(struct v_file* file, struct dir_context* dctx);
int (*write)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
int (*read)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
int (*readdir)(struct v_file* file, struct dir_context* dctx);
- int (*seek)(struct v_inode* inode, size_t offset);
+ int (*seek)(struct v_inode* inode, size_t offset); // optional
int (*close)(struct v_file* file);
int (*sync)(struct v_file* file);
};
int (*close)(struct v_file* file);
int (*sync)(struct v_file* file);
};
int (*rename)(struct v_inode* from_inode,
struct v_dnode* from_dnode,
struct v_dnode* to_dnode);
int (*rename)(struct v_inode* from_inode,
struct v_dnode* from_dnode,
struct v_dnode* to_dnode);
- int (*getxattr)(struct v_inode* this, struct v_xattr_entry* entry);
- int (*setxattr)(struct v_inode* this, struct v_xattr_entry* entry);
- int (*delxattr)(struct v_inode* this, struct v_xattr_entry* entry);
+ int (*getxattr)(struct v_inode* this,
+ struct v_xattr_entry* entry); // optional
+ int (*setxattr)(struct v_inode* this,
+ struct v_xattr_entry* entry); // optional
+ int (*delxattr)(struct v_inode* this,
+ struct v_xattr_entry* entry); // optional
struct v_dnode* mnt_point;
struct v_superblock* super_block;
uint32_t busy_counter;
struct v_dnode* mnt_point;
struct v_superblock* super_block;
uint32_t busy_counter;
-vfs_mount(const char* target, const char* fs_name, struct device* device);
+vfs_mount(const char* target,
+ const char* fs_name,
+ struct device* device,
+ int options);
int
vfs_unmount(const char* target);
int
vfs_unmount(const char* target);
int
vfs_mount_at(const char* fs_name,
struct device* device,
int
vfs_mount_at(const char* fs_name,
struct device* device,
- struct v_dnode* mnt_point);
+ struct v_dnode* mnt_point,
+ int options);
int
vfs_unmount_at(struct v_dnode* mnt_point);
int
vfs_unmount_at(struct v_dnode* mnt_point);
struct v_mount*
vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point);
struct v_mount*
vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point);
+int
+vfs_check_writable(struct v_dnode* dnode);
+
int
default_file_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
int
default_file_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
#define ERANGE -23
#define ENOMEM LXOUTOFMEM
#define ENOTDEV -24
#define ERANGE -23
#define ENOMEM LXOUTOFMEM
#define ENOTDEV -24
#endif /* __LUNAIX_CODE_H */
#endif /* __LUNAIX_CODE_H */
+#include <lunaix/foptions.h>
#include <lunaix/fs.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/process.h>
#include <lunaix/fs.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/process.h>
if (vfs_sysroot->mnt && (errno = vfs_unmount_at(vfs_sysroot))) {
return errno;
}
if (vfs_sysroot->mnt && (errno = vfs_unmount_at(vfs_sysroot))) {
return errno;
}
- return vfs_mount_at(fs_name, device, vfs_sysroot);
+ return vfs_mount_at(fs_name, device, vfs_sysroot, 0);
-vfs_mount(const char* target, const char* fs_name, struct device* device)
+vfs_mount(const char* target,
+ const char* fs_name,
+ struct device* device,
+ int options)
{
int errno;
struct v_dnode* mnt;
if (!(errno =
vfs_walk(__current->cwd, target, &mnt, NULL, VFS_WALK_MKPARENT))) {
{
int errno;
struct v_dnode* mnt;
if (!(errno =
vfs_walk(__current->cwd, target, &mnt, NULL, VFS_WALK_MKPARENT))) {
- errno = vfs_mount_at(fs_name, device, mnt);
+ errno = vfs_mount_at(fs_name, device, mnt, options);
int
vfs_mount_at(const char* fs_name,
struct device* device,
int
vfs_mount_at(const char* fs_name,
struct device* device,
- struct v_dnode* mnt_point)
+ struct v_dnode* mnt_point,
+ int options)
{
if (mnt_point->inode && !(mnt_point->inode->itype & VFS_IFDIR)) {
return ENOTDIR;
{
if (mnt_point->inode && !(mnt_point->inode->itype & VFS_IFDIR)) {
return ENOTDIR;
errno = ENOMEM;
goto cleanup;
}
errno = ENOMEM;
goto cleanup;
}
+
+ mnt_point->mnt->flags = options;
-__DEFINE_LXSYSCALL3(int,
+int
+vfs_check_writable(struct v_dnode* dnode)
+{
+ if ((dnode->mnt->flags & MNT_RO)) {
+ return EROFS;
+ }
+ return 0;
+}
+
+__DEFINE_LXSYSCALL4(int,
mount,
const char*,
source,
const char*,
target,
const char*,
mount,
const char*,
source,
const char*,
target,
const char*,
+ fstype,
+ int,
+ options)
{
struct v_dnode *dev, *mnt;
int errno = 0;
{
struct v_dnode *dev, *mnt;
int errno = 0;
- errno = vfs_mount_at(fstype, device, mnt);
+ errno = vfs_mount_at(fstype, device, mnt, options);
done:
return DO_STATUS(errno);
done:
return DO_STATUS(errno);
int i = 0, j = 0;
if (depth >= VFS_SYMLINK_DEPTH) {
int i = 0, j = 0;
if (depth >= VFS_SYMLINK_DEPTH) {
}
if (path[0] == VFS_PATH_DELIM || !start) {
}
if (path[0] == VFS_PATH_DELIM || !start) {
struct v_dnode* dnode;
struct v_inode* current_inode;
struct v_dnode* current_level = start;
struct v_dnode* dnode;
struct v_inode* current_inode;
struct v_dnode* current_level = start;
struct hstr name = HSTR(fname_buffer, 0);
char current = path[i++], lookahead;
struct hstr name = HSTR(fname_buffer, 0);
char current = path[i++], lookahead;
- while (current && current_level) {
lookahead = path[i++];
if (current != VFS_PATH_DELIM) {
if (j >= VFS_NAME_MAXLEN - 1) {
lookahead = path[i++];
if (current != VFS_PATH_DELIM) {
if (j >= VFS_NAME_MAXLEN - 1) {
// 创建一个根dnode。
vfs_sysroot = vfs_d_alloc(NULL, &vfs_empty);
// 创建一个根dnode。
vfs_sysroot = vfs_d_alloc(NULL, &vfs_empty);
+ vfs_sysroot->parent = vfs_sysroot;
atomic_fetch_add(&vfs_sysroot->ref_count, 1);
}
atomic_fetch_add(&vfs_sysroot->ref_count, 1);
}
return parent;
if (HSTR_EQ(str, &vfs_ddot)) {
return parent;
if (HSTR_EQ(str, &vfs_ddot)) {
- return parent->parent ? parent->parent : parent;
}
uint32_t hash = str->hash;
}
uint32_t hash = str->hash;
+ if ((errno = vfs_check_writable(to_link))) {
+ return errno;
+ }
+
lock_inode(to_link->inode);
if (to_link->super_block->root != name->super_block->root) {
errno = EXDEV;
lock_inode(to_link->inode);
if (to_link->super_block->root != name->super_block->root) {
errno = EXDEV;
int
vfs_fsync(struct v_file* file)
{
int
vfs_fsync(struct v_file* file)
{
+ int errno;
+ if ((errno = vfs_check_writable(file->dnode))) {
+ return errno;
+ }
+
pcache_commit_all(file->inode);
pcache_commit_all(file->inode);
if (file->ops->sync) {
errno = file->ops->sync(file);
}
if (file->ops->sync) {
errno = file->ops->sync(file);
}
char name_str[VFS_NAME_MAXLEN];
struct hstr name = HSTR(name_str, 0);
int errno;
char name_str[VFS_NAME_MAXLEN];
struct hstr name = HSTR(name_str, 0);
int errno;
- if ((errno =
- vfs_walk(__current->cwd, path, fdir, &name, VFS_WALK_PARENT))) {
+ if ((errno = vfs_walk_proc(path, fdir, &name, VFS_WALK_PARENT))) {
}
struct v_file* file = fd_s->file;
}
struct v_file* file = fd_s->file;
+
+ if ((errno = vfs_check_writable(file->dnode))) {
+ goto done;
+ }
+
if ((file->inode->itype & VFS_IFDIR)) {
errno = EISDIR;
goto done;
if ((file->inode->itype & VFS_IFDIR)) {
errno = EISDIR;
goto done;
struct v_file* file = fd_s->file;
struct v_file* file = fd_s->file;
+ if (!file->ops->seek) {
+ errno = ENOTSUP;
+ goto done;
+ }
+
- size_t fpos = file->f_pos;
+ int overflow = 0;
+ int fpos = file->f_pos;
switch (options) {
case FSEEK_CUR:
switch (options) {
case FSEEK_CUR:
- fpos = (size_t)((int)file->f_pos + offset);
+ overflow = __builtin_sadd_overflow((int)file->f_pos, offset, &fpos);
- fpos = (size_t)((int)file->inode->fsize + offset);
+ overflow =
+ __builtin_sadd_overflow((int)file->inode->fsize, offset, &fpos);
break;
case FSEEK_SET:
fpos = offset;
break;
}
break;
case FSEEK_SET:
fpos = offset;
break;
}
- if (!(errno = file->ops->seek(file->inode, fpos))) {
+ if (overflow) {
+ errno = EOVERFLOW;
+ } else if (!(errno = file->ops->seek(file->inode, fpos))) {
int
vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
{
int
vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
{
+ if (!dnode || dnode->parent == dnode) {
return 0;
}
if (depth > 64) {
return 0;
}
if (depth > 64) {
}
size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1);
}
size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1);
+ buf[len++] = VFS_PATH_DELIM;
+
size_t cpy_size = MIN(dnode->name.len, size - len);
strncpy(buf + len, dnode->name.value, cpy_size);
len += cpy_size;
size_t cpy_size = MIN(dnode->name.len, size - len);
strncpy(buf + len, dnode->name.value, cpy_size);
len += cpy_size;
- if (len < size) {
- buf[len++] = VFS_PATH_DELIM;
- }
-
{
int errno;
struct v_dnode* dnode;
{
int errno;
struct v_dnode* dnode;
- if (!(errno =
- vfs_walk(__current->cwd, path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
+ if (!(errno = vfs_walk_proc(path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
errno = vfs_readlink(dnode, buf, size);
}
errno = vfs_readlink(dnode, buf, size);
}
{
int errno;
struct v_dnode* dnode;
{
int errno;
struct v_dnode* dnode;
- if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
+ if ((errno = vfs_walk_proc(pathname, &dnode, NULL, 0))) {
return DO_STATUS(errno);
}
lock_dnode(dnode);
return DO_STATUS(errno);
}
lock_dnode(dnode);
+ if ((errno = vfs_check_writable(dnode))) {
+ goto done;
+ }
+
if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
errno = EROFS;
goto done;
if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
errno = EROFS;
goto done;
char name_value[VFS_NAME_MAXLEN];
struct hstr name = HHSTR(name_value, 0, 0);
char name_value[VFS_NAME_MAXLEN];
struct hstr name = HHSTR(name_value, 0, 0);
- if (!dir) {
- errno = ENOMEM;
+ if ((errno = vfs_walk_proc(path, &parent, &name, VFS_WALK_PARENT))) {
- if ((errno =
- vfs_walk(__current->cwd, path, &parent, &name, VFS_WALK_PARENT))) {
+ if ((errno = vfs_check_writable(parent))) {
- dir = vfs_d_alloc(parent, &name);
+ if (!(dir = vfs_d_alloc(parent, &name))) {
+ errno = ENOMEM;
+ goto done;
+ }
lock_dnode(parent);
lock_inode(parent->inode);
lock_dnode(parent);
lock_inode(parent->inode);
int
__vfs_do_unlink(struct v_dnode* dnode)
{
int
__vfs_do_unlink(struct v_dnode* dnode)
{
struct v_inode* inode = dnode->inode;
if (dnode->ref_count > 1) {
return EBUSY;
}
struct v_inode* inode = dnode->inode;
if (dnode->ref_count > 1) {
return EBUSY;
}
+ if ((errno = vfs_check_writable(dnode))) {
+ return errno;
+ }
+
if (inode->open_count) {
errno = EBUSY;
} else if (!(inode->itype & VFS_IFDIR)) {
if (inode->open_count) {
errno = EBUSY;
} else if (!(inode->itype & VFS_IFDIR)) {
{
int errno;
struct v_dnode* dnode;
{
int errno;
struct v_dnode* dnode;
- if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
- goto done;
- }
- if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
- errno = EROFS;
+ if ((errno = vfs_walk_proc(pathname, &dnode, NULL, 0))) {
{
int errno;
struct v_fd* fd_s;
{
int errno;
struct v_fd* fd_s;
if (!(errno = vfs_getfd(fildes, &fd_s))) {
errno = vfs_fsync(fd_s->file);
}
if (!(errno = vfs_getfd(fildes, &fd_s))) {
errno = vfs_fsync(fd_s->file);
}
{
int errno;
struct v_dnode* dnode;
{
int errno;
struct v_dnode* dnode;
- if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
+ if ((errno = vfs_walk_proc(pathname, &dnode, NULL, 0))) {
- if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
- errno = EROFS;
+
+ if (errno = vfs_check_writable(dnode)) {
if (!dnode->inode->ops->set_symlink) {
errno = ENOTSUP;
goto done;
if (!dnode->inode->ops->set_symlink) {
errno = ENOTSUP;
goto done;
struct v_dnode* dnode;
int errno = 0;
struct v_dnode* dnode;
int errno = 0;
- if ((errno = vfs_walk(__current->cwd, path, &dnode, NULL, 0))) {
+ if ((errno = vfs_walk_proc(path, &dnode, NULL, 0))) {
int
vfs_do_rename(struct v_dnode* current, struct v_dnode* target)
{
int
vfs_do_rename(struct v_dnode* current, struct v_dnode* target)
{
if (current->inode->id == target->inode->id) {
// hard link
return 0;
}
if (current->inode->id == target->inode->id) {
// hard link
return 0;
}
+ if (errno = vfs_check_writable(current)) {
+ return errno;
+ }
+
if (current->ref_count > 1 || target->ref_count > 1) {
return EBUSY;
}
if (current->ref_count > 1 || target->ref_count > 1) {
return EBUSY;
}
struct v_dnode* oldparent = current->parent;
struct v_dnode* newparent = target->parent;
struct v_dnode* oldparent = current->parent;
struct v_dnode* newparent = target->parent;
struct hstr name = HSTR(valloc(VFS_NAME_MAXLEN), 0);
int errno = 0;
struct hstr name = HSTR(valloc(VFS_NAME_MAXLEN), 0);
int errno = 0;
- if ((errno = vfs_walk(__current->cwd, oldpath, &cur, NULL, 0))) {
+ if ((errno = vfs_walk_proc(oldpath, &cur, NULL, 0))) {
#include <lunaix/tty/tty.h>
#include <lunaix/device.h>
#include <lunaix/tty/tty.h>
#include <lunaix/device.h>
+#include <lunaix/foptions.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/page.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/page.h>
#include <lunaix/mm/pmm.h>
}
// FIXME replace with more specific fs for device.
}
// FIXME replace with more specific fs for device.
- vfs_mount("/dev", "twifs", NULL);
+ vfs_mount("/dev", "twifs", NULL, MNT_RO);