From 6c00aabc9e209639ff2753ba8cc2acf3f1b5ec95 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 12 Nov 2009 19:14:42 +0000 Subject: [PATCH] Implemented POSIX.1-2008 functions unlinkat(), symlinkat(), mkdirat(), utimensat(), and futimens(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34010 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/posix/fcntl.h | 1 + headers/posix/sys/stat.h | 13 +++++ headers/posix/unistd.h | 8 ++- src/system/libroot/posix/sys/mkdir.c | 23 ++++---- src/system/libroot/posix/sys/utimes.c | 70 ++++++++++++++++++++++--- src/system/libroot/posix/unistd/Jamfile | 2 +- src/system/libroot/posix/unistd/link.c | 26 ++++++--- 7 files changed, 114 insertions(+), 29 deletions(-) diff --git a/headers/posix/fcntl.h b/headers/posix/fcntl.h index 591565b80b..36134aa1c5 100644 --- a/headers/posix/fcntl.h +++ b/headers/posix/fcntl.h @@ -70,6 +70,7 @@ #define AT_SYMLINK_NOFOLLOW 0x1 /* fstatat(), fchmodat(), fchownat(), utimensat() */ #define AT_SYMLINK_FOLLOW 0x2 /* linkat() */ +#define AT_REMOVEDIR 0x04 /* unlinkat() */ #endif /* advisory file locking */ diff --git a/headers/posix/sys/stat.h b/headers/posix/sys/stat.h index 6f7ee499a5..615b6131d9 100644 --- a/headers/posix/sys/stat.h +++ b/headers/posix/sys/stat.h @@ -101,6 +101,10 @@ struct stat { #define DEFFILEMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) /* default file mode, everyone can read/write */ +/* special values for timespec::tv_nsec passed to utimensat(), futimens() */ +#define UTIME_NOW 1000000000 +#define UTIME_OMIT 1000000001 + #ifdef __cplusplus extern "C" { #endif @@ -114,9 +118,18 @@ extern int lstat(const char *path, struct stat *st); extern int fstatat(int fd, const char *path, struct stat *st, int flag); #endif extern int mkdir(const char *path, mode_t mode); +#ifdef B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT +extern int mkdirat(int fd, const char *path, mode_t mode); +#endif extern int mkfifo(const char *path, mode_t mode); extern mode_t umask(mode_t cmask); +#ifdef B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT +extern int utimensat(int fd, const char *path, + const struct timespec times[2], int flag); +#endif +extern int futimens(int fd, const struct timespec times[2]); + #ifdef __cplusplus } #endif diff --git a/headers/posix/unistd.h b/headers/posix/unistd.h index e5107b0e5a..7b2e178659 100644 --- a/headers/posix/unistd.h +++ b/headers/posix/unistd.h @@ -135,6 +135,9 @@ extern int dup2(int fd1, int fd2); extern int close(int fd); extern int link(const char *name, const char *new_name); extern int unlink(const char *name); +#ifdef B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT +extern int unlinkat(int fd, const char *path, int flag); +#endif extern int rmdir(const char *path); extern ssize_t readlink(const char *path, char *buffer, size_t bufferSize); @@ -142,7 +145,10 @@ extern ssize_t readlink(const char *path, char *buffer, size_t bufferSize); extern ssize_t readlinkat(int fd, const char *path, char *buffer, size_t bufferSize); #endif -extern int symlink(const char *from, const char *to); +extern int symlink(const char *toPath, const char *symlinkPath); +#ifdef B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT +extern int symlinkat(const char *toPath, int fd, const char *symlinkPath); +#endif extern int ftruncate(int fd, off_t newSize); extern int truncate(const char *path, off_t newSize); diff --git a/src/system/libroot/posix/sys/mkdir.c b/src/system/libroot/posix/sys/mkdir.c index 1ca6fab31e..8bcfe4163a 100644 --- a/src/system/libroot/posix/sys/mkdir.c +++ b/src/system/libroot/posix/sys/mkdir.c @@ -4,25 +4,26 @@ */ +#define B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT 1 + // make the *at() functions and AT_* macros visible + #include #include #include +#include #include -#define RETURN_AND_SET_ERRNO(err) \ - if (err < 0) { \ - errno = err; \ - return -1; \ - } \ - return err; - - int mkdir(const char* path, mode_t mode) { - status_t status = _kern_create_dir(-1, path, mode & ~__gUmask); - - RETURN_AND_SET_ERRNO(status); + RETURN_AND_SET_ERRNO(_kern_create_dir(-1, path, mode & ~__gUmask)); +} + + +int +mkdirat(int fd, const char *path, mode_t mode) +{ + RETURN_AND_SET_ERRNO(_kern_create_dir(fd, path, mode & ~__gUmask)); } diff --git a/src/system/libroot/posix/sys/utimes.c b/src/system/libroot/posix/sys/utimes.c index 717ea0c49d..9cbd20c612 100644 --- a/src/system/libroot/posix/sys/utimes.c +++ b/src/system/libroot/posix/sys/utimes.c @@ -1,9 +1,13 @@ /* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2006-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ +#define B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT 1 + // make the *at() functions and AT_* macros visible + #include #include @@ -11,14 +15,7 @@ #include #include - - -#define RETURN_AND_SET_ERRNO(err) \ - if (err < 0) { \ - errno = err; \ - return -1; \ - } \ - return err; +#include int @@ -45,3 +42,60 @@ utimes(const char* path, const struct timeval times[2]) RETURN_AND_SET_ERRNO(status); } + +int +utimensat(int fd, const char *path, const struct timespec times[2], int flag) +{ + struct stat stat; + status_t status; + uint32 mask = 0; + + // Init the stat time fields to the current time, if at least one time is + // supposed to be set to it. + if (times == NULL || times[0].tv_nsec == UTIME_NOW + || times[1].tv_nsec == UTIME_NOW) { + bigtime_t now = real_time_clock_usecs(); + stat.st_atim.tv_sec = stat.st_mtim.tv_sec = now / 1000000; + stat.st_atim.tv_nsec = stat.st_mtim.tv_nsec = (now % 1000000) * 1000; + } + + if (times != NULL) { + // access time + if (times[0].tv_nsec != UTIME_OMIT) { + mask |= B_STAT_ACCESS_TIME; + + if (times[0].tv_nsec != UTIME_NOW) { + if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) + RETURN_AND_SET_ERRNO(EINVAL); + } + + stat.st_atim = times[0]; + } + + // modified time + if (times[1].tv_nsec != UTIME_OMIT) { + mask |= B_STAT_MODIFICATION_TIME; + + if (times[1].tv_nsec != UTIME_NOW) { + if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) + RETURN_AND_SET_ERRNO(EINVAL); + } + + stat.st_mtim = times[1]; + } + } + + // set the times -- as per spec we even need to do this, if both have + // UTIME_OMIT set + status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) != 0, + &stat, sizeof(struct stat), mask); + + RETURN_AND_SET_ERRNO(status); +} + + +int +futimens(int fd, const struct timespec times[2]) +{ + return utimensat(fd, NULL, times, 0); +} diff --git a/src/system/libroot/posix/unistd/Jamfile b/src/system/libroot/posix/unistd/Jamfile index b5a972856b..05429f9fda 100644 --- a/src/system/libroot/posix/unistd/Jamfile +++ b/src/system/libroot/posix/unistd/Jamfile @@ -1,7 +1,7 @@ SubDir HAIKU_TOP src system libroot posix unistd ; UsePrivateSystemHeaders ; -UsePrivateHeaders libroot runtime_loader ; +UsePrivateHeaders libroot runtime_loader shared ; MergeObject posix_unistd.o : access.c diff --git a/src/system/libroot/posix/unistd/link.c b/src/system/libroot/posix/unistd/link.c index a2126cdb08..58e18049a1 100644 --- a/src/system/libroot/posix/unistd/link.c +++ b/src/system/libroot/posix/unistd/link.c @@ -10,14 +10,7 @@ #include #include #include - - -#define RETURN_AND_SET_ERRNO(err) \ - if (err < 0) { \ - errno = err; \ - return -1; \ - } \ - return err; +#include ssize_t @@ -55,6 +48,13 @@ symlink(const char *toPath, const char *symlinkPath) } +int +symlinkat(const char *toPath, int fd, const char *symlinkPath) +{ + RETURN_AND_SET_ERRNO(_kern_create_symlink(fd, symlinkPath, toPath, 0)); +} + + int unlink(const char *path) { @@ -64,6 +64,16 @@ unlink(const char *path) } +int +unlinkat(int fd, const char *path, int flag) +{ + if ((flag & AT_REMOVEDIR) != 0) + RETURN_AND_SET_ERRNO(_kern_remove_dir(fd, path)); + else + RETURN_AND_SET_ERRNO(_kern_unlink(fd, path)); +} + + int link(const char *toPath, const char *linkPath) {