diff --git a/arch/amd64/syscall.c b/arch/amd64/syscall.c index 2ef4ce0..d96b061 100644 --- a/arch/amd64/syscall.c +++ b/arch/amd64/syscall.c @@ -53,6 +53,8 @@ void *syscall_table[256] = { [SYSCALL_NR_SELECT] = sys_select, [SYSCALL_NR_DUP] = sys_dup, [SYSCALL_NR_DUP2] = sys_dup2, + [SYSCALL_NR_TRUNCATE] = sys_truncate, + [SYSCALL_NR_FTRUNCATE] = sys_ftruncate, [SYSCALL_NR_GETCWD] = sys_getcwd, [SYSCALL_NR_CHDIR] = sys_chdir, [SYSCALL_NR_MKDIRAT] = sys_mkdirat, diff --git a/fs/vfs_ops.c b/fs/vfs_ops.c index 2ffe032..8d0c82d 100644 --- a/fs/vfs_ops.c +++ b/fs/vfs_ops.c @@ -542,6 +542,22 @@ int vfs_fstatat(struct vfs_ioctx *ctx, struct vnode *at, const char *path, struc return node->op->stat(node, st); } +int vfs_ftruncate(struct vfs_ioctx *ctx, struct vnode *node, off_t length) { + _assert(ctx); + _assert(node); + + if (node->type != VN_REG) { + kwarn("truncate() on non-file\n"); + return -EPERM; + } + + if (node->op && node->op->truncate) { + return node->op->truncate(node, length); + } else { + return -ENOSYS; + } +} + ssize_t vfs_write(struct vfs_ioctx *ctx, struct ofile *fd, const void *buf, size_t count) { struct vnode *node; ssize_t b; diff --git a/include/fs/vfs.h b/include/fs/vfs.h index 4ad146b..6169f37 100644 --- a/include/fs/vfs.h +++ b/include/fs/vfs.h @@ -54,6 +54,7 @@ int vfs_mknod(struct vfs_ioctx *ctx, const char *path, mode_t mode, struct vnode int vfs_chmod(struct vfs_ioctx *ctx, const char *path, mode_t mode); int vfs_chown(struct vfs_ioctx *ctx, const char *path, uid_t uid, gid_t gid); int vfs_ioctl(struct vfs_ioctx *ctx, struct ofile *fd, unsigned int cmd, void *arg); +int vfs_ftruncate(struct vfs_ioctx *ctx, struct vnode *node, off_t length); int vfs_faccessat(struct vfs_ioctx *ctx, struct vnode *at, const char *path, int accmode, int flags); int vfs_fstatat(struct vfs_ioctx *ctx, struct vnode *at, const char *path, struct stat *st, int flags); diff --git a/include/sys/sys_file.h b/include/sys/sys_file.h index a739da1..98ae034 100644 --- a/include/sys/sys_file.h +++ b/include/sys/sys_file.h @@ -4,6 +4,8 @@ ssize_t sys_read(int fd, void *data, size_t lim); ssize_t sys_write(int fd, const void *data, size_t lim); +int sys_ftruncate(int fd, off_t length); +int sys_truncate(const char *filename, off_t length); int sys_creat(const char *pathname, int mode); int sys_mkdirat(int dfd, const char *pathname, int mode); int sys_unlinkat(int dfd, const char *pathname, int flags); diff --git a/include/user/syscall.h b/include/user/syscall.h index da2a161..4b5bf4b 100644 --- a/include/user/syscall.h +++ b/include/user/syscall.h @@ -15,6 +15,8 @@ #define SYSCALL_NR_SELECT 23 #define SYSCALL_NR_DUP 32 #define SYSCALL_NR_DUP2 33 +#define SYSCALL_NR_TRUNCATE 76 +#define SYSCALL_NR_FTRUNCATE 77 #define SYSCALL_NR_GETCWD 79 #define SYSCALL_NR_CHDIR 80 #define SYSCALL_NR_MKDIRAT 83 diff --git a/sys/sys_file.c b/sys/sys_file.c index f5f8bae..87158d1 100644 --- a/sys/sys_file.c +++ b/sys/sys_file.c @@ -105,6 +105,31 @@ int sys_unlinkat(int dfd, const char *pathname, int flags) { return vfs_unlinkat(get_ioctx(), at, pathname, flags); } +int sys_truncate(const char *pathname, off_t length) { + userptr_check(pathname); + struct vnode *node; + struct vfs_ioctx *ioctx = get_ioctx(); + int res; + + if ((res = vfs_find(ioctx, ioctx->cwd_vnode, pathname, 0, &node)) != 0) { + return res; + } + + return vfs_ftruncate(ioctx, node, length); +} + +int sys_ftruncate(int fd, off_t length) { + struct ofile *of = get_fd(fd); + if (!of) { + return -EBADF; + } + if (of->flags & OF_SOCKET) { + kwarn("truncate() on socket\n"); + return -EINVAL; + } + return vfs_ftruncate(get_ioctx(), of->file.vnode, length); +} + int sys_chdir(const char *filename) { userptr_check(filename); return vfs_setcwd(get_ioctx(), filename);