diff --git a/docs/SystemEdls.md b/docs/SystemEdls.md index 58a6599078..203ce91da0 100644 --- a/docs/SystemEdls.md +++ b/docs/SystemEdls.md @@ -83,6 +83,7 @@ oe_syscall_link_ocall | link | - | oe_syscall_unlink_ocall | unlink | - | oe_syscall_rename_ocall | rename | - | oe_syscall_truncate_ocall | truncate | - | +oe_syscall_ftruncate_ocall | ftruncate | - | oe_syscall_mkdir_ocall | mkdir | - | oe_syscall_rmdir_ocall | rmdir | - | oe_syscall_fcntl_ocall | fcntl | - | diff --git a/docs/UsingTheIOSubsystem.md b/docs/UsingTheIOSubsystem.md index 5b40f3fb77..7b3b207505 100644 --- a/docs/UsingTheIOSubsystem.md +++ b/docs/UsingTheIOSubsystem.md @@ -382,6 +382,7 @@ functions. | dup2 | none | | fdatasync | none | | fsync | none | +| ftruncate | none | | getcwd | none | | getdomainname | none | | getegid | none | @@ -401,6 +402,7 @@ functions. | read | none | | rmdir | none | | sleep | none | +| truncate | none | | unlink | none | | write | none | | | | diff --git a/host/linux/syscall.c b/host/linux/syscall.c index f0eb835174..9056f92d3d 100644 --- a/host/linux/syscall.c +++ b/host/linux/syscall.c @@ -389,6 +389,13 @@ int oe_syscall_truncate_ocall(const char* path, oe_off_t length) return truncate(path, length); } +int oe_syscall_ftruncate_ocall(oe_host_fd_t fd, oe_off_t length) +{ + errno = 0; + + return ftruncate((int)fd, length); +} + int oe_syscall_mkdir_ocall(const char* pathname, oe_mode_t mode) { errno = 0; diff --git a/host/windows/syscall.c b/host/windows/syscall.c index d7a39db13d..f5e5c3b33f 100644 --- a/host/windows/syscall.c +++ b/host/windows/syscall.c @@ -2032,6 +2032,41 @@ int oe_syscall_truncate_ocall(const char* pathname, oe_off_t length) return ret; } +int oe_syscall_ftruncate_ocall(oe_host_fd_t fd, oe_off_t length) +{ + const HANDLE h = (HANDLE)fd; + LARGE_INTEGER new_offset = {0}; + LARGE_INTEGER old_offset = {0}; + + if (!SetFilePointerEx(h, new_offset, &old_offset, FILE_CURRENT)) + { + _set_errno(_winerr_to_errno(GetLastError())); + return -1; + } + + new_offset.QuadPart = length; + if (!SetFilePointerEx(h, new_offset, NULL, FILE_BEGIN)) + { + _set_errno(_winerr_to_errno(GetLastError())); + return -1; + } + + if (!SetEndOfFile(h)) + { + _set_errno(_winerr_to_errno(GetLastError())); + SetFilePointerEx(h, old_offset, NULL, FILE_BEGIN); + return -1; + } + + if (!SetFilePointerEx(h, old_offset, NULL, FILE_BEGIN)) + { + _set_errno(_winerr_to_errno(GetLastError())); + return -1; + } + + return 0; +} + int oe_syscall_mkdir_ocall(const char* pathname, oe_mode_t mode) { int ret = -1; diff --git a/include/openenclave/edl/fcntl.edl b/include/openenclave/edl/fcntl.edl index 8a6f37389a..5a28f71afa 100644 --- a/include/openenclave/edl/fcntl.edl +++ b/include/openenclave/edl/fcntl.edl @@ -177,6 +177,11 @@ enclave oe_off_t length) propagate_errno; + int oe_syscall_ftruncate_ocall( + oe_host_fd_t fd, + oe_off_t length) + propagate_errno; + int oe_syscall_mkdir_ocall( [in, string] const char* pathname, oe_mode_t mode) diff --git a/include/openenclave/internal/syscall/declarations.h b/include/openenclave/internal/syscall/declarations.h index f5e871e64e..20ba057f34 100644 --- a/include/openenclave/internal/syscall/declarations.h +++ b/include/openenclave/internal/syscall/declarations.h @@ -175,6 +175,7 @@ OE_DECLARE_SYSCALL2(SYS_flock); OE_DECLARE_SYSCALL2(SYS_fstat); OE_DECLARE_SYSCALL4(SYS_fstatat); OE_DECLARE_SYSCALL1_M(SYS_fsync); +OE_DECLARE_SYSCALL2(SYS_ftruncate); // SYS_futex is needed for compiling musl/src/internal/pthread_impl.h // It doesn't have to be implemented. // It is called with 3 or 4 arguments. diff --git a/include/openenclave/internal/syscall/fd.h b/include/openenclave/internal/syscall/fd.h index 02be71b95c..faee04c49e 100644 --- a/include/openenclave/internal/syscall/fd.h +++ b/include/openenclave/internal/syscall/fd.h @@ -66,6 +66,8 @@ typedef struct _oe_file_ops int (*fstat)(oe_fd_t* file, struct oe_stat_t* buf); + int (*ftruncate)(oe_fd_t* file, oe_off_t length); + int (*fsync)(oe_fd_t* file); int (*fdatasync)(oe_fd_t* file); } oe_file_ops_t; diff --git a/include/openenclave/internal/syscall/unistd.h b/include/openenclave/internal/syscall/unistd.h index 4bf41c3527..e541e8aa04 100644 --- a/include/openenclave/internal/syscall/unistd.h +++ b/include/openenclave/internal/syscall/unistd.h @@ -52,6 +52,8 @@ int oe_truncate(const char* path, oe_off_t length); int oe_truncate_d(uint64_t devid, const char* path, oe_off_t length); +int oe_ftruncate(int fd, oe_off_t length); + #endif /* !defined(WIN32) */ int oe_link(const char* oldpath, const char* newpath); diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 6405f5686a..c4d4b63dd1 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -782,6 +782,7 @@ add_enclave_library( ${MUSLSRC}/unistd/close.c ${MUSLSRC}/unistd/fdatasync.c ${MUSLSRC}/unistd/fsync.c + ${MUSLSRC}/unistd/ftruncate.c ${MUSLSRC}/unistd/getgid.c ${MUSLSRC}/unistd/getegid.c ${MUSLSRC}/unistd/getuid.c diff --git a/syscall/consolefs.c b/syscall/consolefs.c index 2da7c52454..1c1f7b1c29 100644 --- a/syscall/consolefs.c +++ b/syscall/consolefs.c @@ -490,6 +490,15 @@ static int _consolefs_fstat(oe_fd_t* file, struct oe_stat_t* buf) return -1; } +static int _consolefs_ftruncate(oe_fd_t* file, oe_off_t length) +{ + OE_UNUSED(file); + OE_UNUSED(length); + OE_RAISE_ERRNO(OE_EINVAL); +done: + return -1; +} + static int _consolefs_fsync(oe_fd_t* file) { OE_UNUSED(file); @@ -513,6 +522,7 @@ static oe_file_ops_t _ops = { .pwrite = _consolefs_pwrite, .getdents64 = _consolefs_getdents64, .fstat = _consolefs_fstat, + .ftruncate = _consolefs_ftruncate, .fsync = _consolefs_fsync, .fdatasync = _consolefs_fsync, }; diff --git a/syscall/devices/hostfs/hostfs.c b/syscall/devices/hostfs/hostfs.c index c03c55b5b2..66a94d7f69 100644 --- a/syscall/devices/hostfs/hostfs.c +++ b/syscall/devices/hostfs/hostfs.c @@ -1359,6 +1359,24 @@ static int _hostfs_truncate( return ret; } +static int _hostfs_ftruncate(oe_fd_t* desc, oe_off_t length) +{ + int ret = -1; + const file_t* const file = _cast_file(desc); + int retval = -1; + + if (!file) + OE_RAISE_ERRNO(OE_EINVAL); + + if (oe_syscall_ftruncate_ocall(&retval, file->host_fd, length) != OE_OK) + OE_RAISE_ERRNO(OE_EINVAL); + + ret = retval; + +done: + return ret; +} + static int _hostfs_mkdir( oe_device_t* device, const char* pathname, @@ -1441,6 +1459,7 @@ static oe_file_ops_t _file_ops = .pwrite = _hostfs_pwrite, .getdents64 = _hostfs_getdents64, .fstat = _hostfs_fstat, + .ftruncate = _hostfs_ftruncate, .fsync = _hostfs_fsync, .fdatasync = _hostfs_fdatasync, }; diff --git a/syscall/fdtable.c b/syscall/fdtable.c index c38aa762c3..a23559d859 100644 --- a/syscall/fdtable.c +++ b/syscall/fdtable.c @@ -170,6 +170,7 @@ static void _assert_fd(oe_fd_t* desc) oe_assert(desc->ops.file.pwrite); oe_assert(desc->ops.file.getdents64); oe_assert(desc->ops.file.fstat); + oe_assert(desc->ops.file.ftruncate); oe_assert(desc->ops.file.fsync); oe_assert(desc->ops.file.fdatasync); break; diff --git a/syscall/syscall.c b/syscall/syscall.c index db7fd5ce3f..e81bcfa61d 100644 --- a/syscall/syscall.c +++ b/syscall/syscall.c @@ -316,6 +316,14 @@ OE_WEAK OE_DEFINE_SYSCALL1_M(SYS_fsync) return oe_fsync(fd); } +OE_WEAK OE_DEFINE_SYSCALL2(SYS_ftruncate) +{ + oe_errno = 0; + const int fd = (int)arg1; + const ssize_t length = (ssize_t)arg2; + return oe_ftruncate(fd, length); +} + OE_WEAK OE_DEFINE_SYSCALL3_M(SYS_futex) { OE_UNUSED(arg1); @@ -1107,6 +1115,7 @@ static long _syscall( OE_SYSCALL_DISPATCH(SYS_flock, arg1, arg2); OE_SYSCALL_DISPATCH(SYS_fstat, arg1, arg2); OE_SYSCALL_DISPATCH(SYS_fsync, arg1); + OE_SYSCALL_DISPATCH(SYS_ftruncate, arg1, arg2); OE_SYSCALL_DISPATCH(SYS_getcwd, arg1, arg2); OE_SYSCALL_DISPATCH(SYS_getdents64, arg1, arg2, arg3); OE_SYSCALL_DISPATCH(SYS_getegid); diff --git a/syscall/unistd.c b/syscall/unistd.c index 67af74764b..943528b517 100644 --- a/syscall/unistd.c +++ b/syscall/unistd.c @@ -545,6 +545,20 @@ int oe_truncate_d(uint64_t devid, const char* path, oe_off_t length) return ret; } +int oe_ftruncate(int fd, oe_off_t length) +{ + int ret = -1; + oe_fd_t* file; + + if (!(file = oe_fdtable_get(fd, OE_FD_TYPE_FILE))) + OE_RAISE_ERRNO(oe_errno); + + ret = file->ops.file.ftruncate(file, length); + +done: + return ret; +} + oe_off_t oe_lseek(int fd, oe_off_t offset, int whence) { oe_off_t ret = -1; diff --git a/tests/syscall/fs/enc/enc.cpp b/tests/syscall/fs/enc/enc.cpp index 2161003a02..59ca3455bc 100644 --- a/tests/syscall/fs/enc/enc.cpp +++ b/tests/syscall/fs/enc/enc.cpp @@ -397,7 +397,7 @@ static void test_truncate_file(FILE_SYSTEM& fs, const char* tmp_dir) mkpath(path, tmp_dir, "alphabet"); - /* Remove the file. */ + /* Truncate the file. */ OE_TEST(fs.truncate(path, 5) == 0); /* Stat the file. */ @@ -405,6 +405,27 @@ static void test_truncate_file(FILE_SYSTEM& fs, const char* tmp_dir) OE_TEST(buf.st_size == 5); } +template +static void test_ftruncate_file(FILE_SYSTEM& fs, const char* tmp_dir) +{ + char path[OE_PAGE_SIZE]; + typename FILE_SYSTEM::stat_type buf; + + printf("--- %s()\n", __FUNCTION__); + + mkpath(path, tmp_dir, "alphabet"); + + /* Truncate the file. */ + const auto file = fs.open(path, O_WRONLY, 0); + OE_TEST(file); + OE_TEST(fs.ftruncate(file, 4) == 0); + OE_TEST(fs.close(file) == 0); + + /* Stat the file. */ + OE_TEST(fs.stat(path, &buf) == 0); + OE_TEST(buf.st_size == 4); +} + template static void test_unlink_file(FILE_SYSTEM& fs, const char* tmp_dir) { @@ -444,6 +465,7 @@ void test_common(FILE_SYSTEM& fs, const char* tmp_dir) test_rename_file(fs, tmp_dir); test_readdir(fs, tmp_dir); test_truncate_file(fs, tmp_dir); + test_ftruncate_file(fs, tmp_dir); test_unlink_file(fs, tmp_dir); test_invalid_path(fs); cleanup(fs, tmp_dir); diff --git a/tests/syscall/fs/enc/file_system.h b/tests/syscall/fs/enc/file_system.h index 76f4608a06..317cdcdd36 100644 --- a/tests/syscall/fs/enc/file_system.h +++ b/tests/syscall/fs/enc/file_system.h @@ -146,6 +146,11 @@ class oe_fd_file_system return oe_truncate(path, length); } + int ftruncate(file_handle file, off_t length) + { + return oe_ftruncate(file, length); + } + private: }; @@ -306,6 +311,11 @@ class fd_file_system return ::truncate(path, length); } + int ftruncate(file_handle file, off_t length) + { + return ::ftruncate(file, length); + } + private: }; @@ -584,6 +594,11 @@ class stream_file_system return ::truncate(path, length); } + int ftruncate(file_handle file, off_t length) + { + return ::ftruncate(fileno(file), length); + } + private: };