Skip to content

Commit

Permalink
vfs: fix seek, add fchmodat
Browse files Browse the repository at this point in the history
  • Loading branch information
moodyhunter committed Jan 1, 2024
1 parent bba7f1b commit 514aede
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 48 deletions.
75 changes: 27 additions & 48 deletions kernel/filesystem/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,74 +110,39 @@ static off_t vfs_io_ops_seek(io_t *io, off_t offset, io_seek_whence_t whence)
{
file_t *file = container_of(io, file_t, io);

if (file_get_ops(file)->seek)
return file_get_ops(file)->seek(file, offset, whence); // use the filesystem's lseek if it exists
const file_ops_t *const ops = file_get_ops(file);
if (ops->seek)
return ops->seek(file, offset, whence); // use the filesystem's lseek if it exists

spinlock_acquire(&file->offset_lock);

off_t ret = 0;
switch (whence)
{
case IO_SEEK_SET:
{
if (unlikely(offset < 0))
{
ret = 0;
break;
}

if ((size_t) offset > file->dentry->inode->size)
ret = file->dentry->inode->size; // beyond the end of the file
else
ret = offset;

file->offset = ret;
file->offset = MAX(offset, 0);
break;
}
case IO_SEEK_CURRENT:
{
if (offset < 0)
{
if (file->offset < (size_t) -offset)
ret = 0; // before the beginning of the file
else
ret = file->offset + offset;
}
else
{
if (file->offset + offset > file->dentry->inode->size)
ret = file->dentry->inode->size; // beyond the end of the file
else
ret = file->offset + offset;
}

file->offset = ret;
off_t new_offset = file->offset + offset;
new_offset = MAX(new_offset, 0);
file->offset = new_offset;
break;
}
case IO_SEEK_END:
{
if (offset < 0)
{
if (file->dentry->inode->size < (size_t) -offset)
ret = 0; // before the beginning of the file
else
ret = file->dentry->inode->size + offset;
}
else
{
// don't allow seeking past the end of the file, (yet)
pr_warn("vfs: seeking past the end of the file is not supported yet");
}

file->offset = ret;
off_t new_offset = file->dentry->inode->size + offset;
new_offset = MAX(new_offset, 0);
file->offset = new_offset;
break;
}
case IO_SEEK_DATA: mos_warn("vfs: IO_SEEK_DATA is not supported"); break;
case IO_SEEK_HOLE: mos_warn("vfs: IO_SEEK_HOLE is not supported"); break;
};

spinlock_release(&file->offset_lock);
return ret;
return file->offset;
}

static vmfault_result_t vfs_fault_handler(vmap_t *vmap, ptr_t fault_addr, pagefault_t *info)
Expand Down Expand Up @@ -553,7 +518,7 @@ long vfs_fstatat(fd_t fd, const char *path, file_stat_t *restrict statbuf, fstat

pr_dinfo2(vfs, "vfs_fstatat(fd=%d, path='%s', stat=%p, flags=%x)", fd, path, (void *) statbuf, flags);
dentry_t *basedir = path_is_absolute(path) ? root_dentry : dentry_from_fd(fd);
lastseg_resolve_flags_t resolve_flags = RESOLVE_EXPECT_FILE | RESOLVE_EXPECT_DIR | RESOLVE_EXPECT_EXIST;
lastseg_resolve_flags_t resolve_flags = RESOLVE_EXPECT_ANY_TYPE | RESOLVE_EXPECT_EXIST;
if (flags & FSTATAT_NOFOLLOW)
resolve_flags |= RESOLVE_SYMLINK_NOFOLLOW;

Expand All @@ -570,7 +535,7 @@ long vfs_fstatat(fd_t fd, const char *path, file_stat_t *restrict statbuf, fstat
size_t vfs_readlinkat(fd_t dirfd, const char *path, char *buf, size_t size)
{
dentry_t *base = path_is_absolute(path) ? root_dentry : dentry_from_fd(dirfd);
dentry_t *dentry = dentry_get(base, root_dentry, path, RESOLVE_SYMLINK_NOFOLLOW | RESOLVE_EXPECT_EXIST);
dentry_t *dentry = dentry_get(base, root_dentry, path, RESOLVE_SYMLINK_NOFOLLOW | RESOLVE_EXPECT_EXIST | RESOLVE_EXPECT_FILE);
if (IS_ERR(dentry))
return PTR_ERR(dentry);

Expand Down Expand Up @@ -733,6 +698,20 @@ ssize_t vfs_getcwd(char *buf, size_t size)
return dentry_path(cwd, root_dentry, buf, size);
}

long vfs_fchmodat(fd_t fd, const char *path, int perm, int flags)
{
pr_dinfo2(vfs, "vfs_fchmodat(fd=%d, path='%s', perm=%o, flags=%x)", fd, path, perm, flags);
dentry_t *base = path_is_absolute(path) ? root_dentry : dentry_from_fd(fd);
dentry_t *dentry = dentry_get(base, root_dentry, path, RESOLVE_EXPECT_EXIST | RESOLVE_EXPECT_ANY_TYPE);
if (IS_ERR(dentry))
return PTR_ERR(dentry);

// TODO: check if the underlying filesystem supports chmod, and is not read-only
dentry->inode->perm = perm;
dentry_unref(dentry);
return 0;
}

// ! sysfs support

static bool vfs_sysfs_filesystems(sysfs_file_t *f)
Expand Down
11 changes: 11 additions & 0 deletions kernel/include/private/mos/filesystem/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,14 @@ long vfs_chdir(const char *path);
* @return ssize_t The size of the path, or 0 if the buffer was too small
*/
ssize_t vfs_getcwd(char *buf, size_t size);

/**
* @brief Change the permissions of a file
*
* @param fd The directory, or a file if FSTATAT_FILE is set
* @param path The path to the file
* @param perm The new permissions
* @param flags fstat_flags flags
* @return long 0 on success, or errno on failure
*/
long vfs_fchmodat(fd_t fd, const char *path, int perm, int flags);
5 changes: 5 additions & 0 deletions kernel/ksyscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -622,3 +622,8 @@ DEFINE_SYSCALL(ssize_t, thread_getname)(tid_t tid, char *buf, size_t buflen)
char *end = strncpy(buf, thread->name, buflen);
return end - buf;
}

DEFINE_SYSCALL(long, vfs_fchmodat)(fd_t dirfd, const char *path, int mode, int flags)
{
return vfs_fchmodat(dirfd, path, mode, flags);
}
11 changes: 11 additions & 0 deletions kernel/ksyscalls.json
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,17 @@
"name": "thread_getname",
"return": "ssize_t",
"arguments": [ { "type": "tid_t", "arg": "tid" }, { "type": "char *", "arg": "buf" }, { "type": "size_t", "arg": "buf_size" } ]
},
{
"number": 61,
"name": "vfs_fchmodat",
"return": "long",
"arguments": [
{ "type": "fd_t", "arg": "dirfd" },
{ "type": "const char *", "arg": "path" },
{ "type": "int", "arg": "mode" },
{ "type": "int", "arg": "flags" }
]
}
]
}

0 comments on commit 514aede

Please sign in to comment.