summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
authored <ed@FreeBSD.org>2015-07-28 12:57:19 +0000
committered <ed@FreeBSD.org>2015-07-28 12:57:19 +0000
commitc07bea4434d945f7c7cca712c357d1481d06682c (patch)
tree73a3cba397026360e888062f9f995caabe71e1f5 /sys/compat
parent6a2604d87526baf5ee286d62d014c0afee6f8e9d (diff)
downloadFreeBSD-src-c07bea4434d945f7c7cca712c357d1481d06682c.zip
FreeBSD-src-c07bea4434d945f7c7cca712c357d1481d06682c.tar.gz
Implement file attribute modification system calls for CloudABI.
CloudABI uses a system call interface to modify file attributes that is more similar to KPI's/FUSE, namely where a stat structure is passed back to the kernel, together with a bitmask of attributes that should be changed. This would allow us to update any set of attributes atomically. That said, I'd rather not go as far as to actually implement it that way, as it would require us to duplicate more code than strictly needed. Let's just stick to the combinations that are actually used by cloudlibc. Obtained from: https://github.com/NuxiNL/freebsd
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/cloudabi/cloudabi_file.c83
1 files changed, 79 insertions, 4 deletions
diff --git a/sys/compat/cloudabi/cloudabi_file.c b/sys/compat/cloudabi/cloudabi_file.c
index 72902ee..45f6583 100644
--- a/sys/compat/cloudabi/cloudabi_file.c
+++ b/sys/compat/cloudabi/cloudabi_file.c
@@ -292,13 +292,64 @@ cloudabi_sys_file_stat_fget(struct thread *td,
return (copyout(&csb, uap->buf, sizeof(csb)));
}
+/* Converts timestamps to arguments to futimens() and utimensat(). */
+static void
+convert_utimens_arguments(const cloudabi_filestat_t *fs,
+ cloudabi_fsflags_t flags, struct timespec *ts)
+{
+
+ if ((flags & CLOUDABI_FILESTAT_ATIM_NOW) != 0) {
+ ts[0].tv_nsec = UTIME_NOW;
+ } else if ((flags & CLOUDABI_FILESTAT_ATIM) != 0) {
+ ts[0].tv_sec = fs->st_atim / 1000000000;
+ ts[0].tv_nsec = fs->st_atim % 1000000000;
+ } else {
+ ts[0].tv_nsec = UTIME_OMIT;
+ }
+
+ if ((flags & CLOUDABI_FILESTAT_MTIM_NOW) != 0) {
+ ts[1].tv_nsec = UTIME_NOW;
+ } else if ((flags & CLOUDABI_FILESTAT_MTIM) != 0) {
+ ts[1].tv_sec = fs->st_mtim / 1000000000;
+ ts[1].tv_nsec = fs->st_mtim % 1000000000;
+ } else {
+ ts[1].tv_nsec = UTIME_OMIT;
+ }
+}
+
int
cloudabi_sys_file_stat_fput(struct thread *td,
struct cloudabi_sys_file_stat_fput_args *uap)
{
+ cloudabi_filestat_t fs;
+ struct timespec ts[2];
+ int error;
- /* Not implemented. */
- return (ENOSYS);
+ error = copyin(uap->buf, &fs, sizeof(fs));
+ if (error != 0)
+ return (error);
+
+ /*
+ * Only support truncation and timestamp modification separately
+ * for now, to prevent unnecessary code duplication.
+ */
+ if ((uap->flags & CLOUDABI_FILESTAT_SIZE) != 0) {
+ /* Call into kern_ftruncate() for file truncation. */
+ if ((uap->flags & ~CLOUDABI_FILESTAT_SIZE) != 0)
+ return (EINVAL);
+ return (kern_ftruncate(td, uap->fd, fs.st_size));
+ } else if ((uap->flags & (CLOUDABI_FILESTAT_ATIM |
+ CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
+ CLOUDABI_FILESTAT_MTIM_NOW)) != 0) {
+ /* Call into kern_futimens() for timestamp modification. */
+ if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM |
+ CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
+ CLOUDABI_FILESTAT_MTIM_NOW)) != 0)
+ return (EINVAL);
+ convert_utimens_arguments(&fs, uap->flags, ts);
+ return (kern_futimens(td, uap->fd, ts, UIO_SYSSPACE));
+ }
+ return (EINVAL);
}
int
@@ -347,9 +398,33 @@ int
cloudabi_sys_file_stat_put(struct thread *td,
struct cloudabi_sys_file_stat_put_args *uap)
{
+ cloudabi_filestat_t fs;
+ struct timespec ts[2];
+ char *path;
+ int error;
- /* Not implemented. */
- return (ENOSYS);
+ /*
+ * Only support timestamp modification for now, as there is no
+ * truncateat().
+ */
+ if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM |
+ CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
+ CLOUDABI_FILESTAT_MTIM_NOW)) != 0)
+ return (EINVAL);
+
+ error = copyin(uap->buf, &fs, sizeof(fs));
+ if (error != 0)
+ return (error);
+ error = copyin_path(uap->path, uap->pathlen, &path);
+ if (error != 0)
+ return (error);
+
+ convert_utimens_arguments(&fs, uap->flags, ts);
+ error = kern_utimensat(td, uap->fd, path, UIO_SYSSPACE, ts,
+ UIO_SYSSPACE, (uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ?
+ 0 : AT_SYMLINK_NOFOLLOW);
+ cloudabi_freestr(path);
+ return (error);
}
int
OpenPOWER on IntegriCloud