Add futimes, futimesat, and lutimes.
Spotted these while cleaning up <sys/cdefs.h> --- if we remove __USE_XOPEN2K8,
libchrome decides you "must" have futimes. Adding the missing functions (all
just alternative interfaces to utimensat(2) system call) lets us clean up
without breaking anything.
Change-Id: If44fab08ee3de0e31066d650d128a3c96323529b
diff --git a/libc/Android.bp b/libc/Android.bp
index 4a44fc6..ba62592 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1373,6 +1373,7 @@
"bionic/syslog.cpp",
"bionic/sys_siglist.c",
"bionic/sys_signame.c",
+ "bionic/sys_time.cpp",
"bionic/system_properties.cpp",
"bionic/tdestroy.cpp",
"bionic/termios.cpp",
@@ -1380,7 +1381,6 @@
"bionic/tmpfile.cpp",
"bionic/umount.cpp",
"bionic/unlink.cpp",
- "bionic/utimes.cpp",
"bionic/wait.cpp",
"bionic/wchar.cpp",
"bionic/wctype.cpp",
diff --git a/libc/bionic/utimes.cpp b/libc/bionic/sys_time.cpp
similarity index 67%
rename from libc/bionic/utimes.cpp
rename to libc/bionic/sys_time.cpp
index 0b66e6c..3d0cd87 100644
--- a/libc/bionic/utimes.cpp
+++ b/libc/bionic/sys_time.cpp
@@ -26,22 +26,40 @@
* SUCH DAMAGE.
*/
+#include <sys/time.h>
+
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <sys/time.h>
#include "private/bionic_time_conversions.h"
-int utimes(const char* path, const timeval tv[2]) {
+static int futimesat(int fd, const char* path, const timeval tv[2], int flags) {
timespec ts[2];
- timespec* ts_ptr = NULL;
- if (tv != NULL) {
- if (!timespec_from_timeval(ts[0], tv[0]) || !timespec_from_timeval(ts[1], tv[1])) {
- errno = EINVAL;
- return -1;
- }
- ts_ptr = ts;
+ if (tv && (!timespec_from_timeval(ts[0], tv[0]) || !timespec_from_timeval(ts[1], tv[1]))) {
+ errno = EINVAL;
+ return -1;
}
- return utimensat(AT_FDCWD, path, ts_ptr, 0);
+ return utimensat(fd, path, tv ? ts : nullptr, flags);
+}
+
+int utimes(const char* path, const timeval tv[2]) {
+ return futimesat(AT_FDCWD, path, tv, 0);
+}
+
+int lutimes(const char* path, const timeval tv[2]) {
+ return futimesat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW);
+}
+
+int futimesat(int fd, const char* path, const timeval tv[2]) {
+ return futimesat(fd, path, tv, 0);
+}
+
+int futimes(int fd, const timeval tv[2]) {
+ timespec ts[2];
+ if (tv && (!timespec_from_timeval(ts[0], tv[0]) || !timespec_from_timeval(ts[1], tv[1]))) {
+ errno = EINVAL;
+ return -1;
+ }
+ return futimens(fd, tv ? ts : nullptr);
}
diff --git a/libc/include/sys/time.h b/libc/include/sys/time.h
index f60c905..f4ed321 100644
--- a/libc/include/sys/time.h
+++ b/libc/include/sys/time.h
@@ -38,13 +38,22 @@
__BEGIN_DECLS
-extern int gettimeofday(struct timeval *, struct timezone *);
-extern int settimeofday(const struct timeval *, const struct timezone *);
+int gettimeofday(struct timeval*, struct timezone*);
+int settimeofday(const struct timeval*, const struct timezone*);
-extern int getitimer(int, struct itimerval *);
-extern int setitimer(int, const struct itimerval *, struct itimerval *);
+int getitimer(int, struct itimerval*);
+int setitimer(int, const struct itimerval*, struct itimerval*);
-extern int utimes(const char *, const struct timeval *);
+int utimes(const char*, const struct timeval*);
+
+#if defined(__USE_BSD)
+int futimes(int, const struct timeval[2]);
+int lutimes(const char*, const struct timeval[2]);
+#endif
+
+#if defined(__USE_GNU)
+int futimesat(int, const char*, const struct timeval[2]);
+#endif
#define timerclear(a) \
((a)->tv_sec = (a)->tv_usec = 0)
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index 7833d05..3928cae 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1273,11 +1273,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index a1b2511..f6520b5 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1273,11 +1273,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index c853f73..603ac86 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1196,11 +1196,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index d893b8b..d2ad249 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1298,11 +1298,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 56d4727..2cf5df0 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1257,11 +1257,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 35c56cb..6c5ba9c 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1257,11 +1257,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index c853f73..603ac86 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1196,11 +1196,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index a58d2bc..1a254ae 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1255,11 +1255,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 2fe730f..ca97c03 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1255,11 +1255,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index c853f73..603ac86 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1196,11 +1196,14 @@
catopen;
endgrent;
endpwent;
+ futimes;
+ futimesat;
getdomainname;
getgrent;
getpwent;
getsubopt;
hasmntopt;
+ lutimes;
mblen;
pthread_getname_np;
quotactl;
diff --git a/tests/sys_time_test.cpp b/tests/sys_time_test.cpp
index 18fbe10..e041ba0 100644
--- a/tests/sys_time_test.cpp
+++ b/tests/sys_time_test.cpp
@@ -22,30 +22,113 @@
#include "TemporaryFile.h"
-TEST(sys_time, utimes) {
- timeval tv[2];
- memset(&tv, 0, sizeof(tv));
+// http://b/11383777
+TEST(sys_time, utimes_nullptr) {
+ TemporaryFile tf;
+ ASSERT_EQ(0, utimes(tf.filename, nullptr));
+}
+
+TEST(sys_time, utimes_EINVAL) {
+ TemporaryFile tf;
+
+ timeval tv[2] = {};
tv[0].tv_usec = -123;
- ASSERT_EQ(-1, utimes("/", tv));
+ ASSERT_EQ(-1, utimes(tf.filename, tv));
ASSERT_EQ(EINVAL, errno);
tv[0].tv_usec = 1234567;
- ASSERT_EQ(-1, utimes("/", tv));
+ ASSERT_EQ(-1, utimes(tf.filename, tv));
ASSERT_EQ(EINVAL, errno);
+
tv[0].tv_usec = 0;
tv[1].tv_usec = -123;
- ASSERT_EQ(-1, utimes("/", tv));
+ ASSERT_EQ(-1, utimes(tf.filename, tv));
ASSERT_EQ(EINVAL, errno);
tv[1].tv_usec = 1234567;
- ASSERT_EQ(-1, utimes("/", tv));
+ ASSERT_EQ(-1, utimes(tf.filename, tv));
ASSERT_EQ(EINVAL, errno);
}
-// http://b/11383777
-TEST(sys_time, utimes_NULL) {
+TEST(sys_time, futimes_nullptr) {
TemporaryFile tf;
- ASSERT_EQ(0, utimes(tf.filename, NULL));
+ ASSERT_EQ(0, futimes(tf.fd, nullptr));
+}
+
+TEST(sys_time, futimes_EINVAL) {
+ TemporaryFile tf;
+
+ timeval tv[2] = {};
+
+ tv[0].tv_usec = -123;
+ ASSERT_EQ(-1, futimes(tf.fd, tv));
+ ASSERT_EQ(EINVAL, errno);
+ tv[0].tv_usec = 1234567;
+ ASSERT_EQ(-1, futimes(tf.fd, tv));
+ ASSERT_EQ(EINVAL, errno);
+
+ tv[0].tv_usec = 0;
+
+ tv[1].tv_usec = -123;
+ ASSERT_EQ(-1, futimes(tf.fd, tv));
+ ASSERT_EQ(EINVAL, errno);
+ tv[1].tv_usec = 1234567;
+ ASSERT_EQ(-1, futimes(tf.fd, tv));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(sys_time, futimesat_nullptr) {
+ TemporaryFile tf;
+ ASSERT_EQ(0, futimesat(AT_FDCWD, tf.filename, nullptr));
+}
+
+TEST(sys_time, futimesat_EINVAL) {
+ TemporaryFile tf;
+
+ timeval tv[2] = {};
+
+ tv[0].tv_usec = -123;
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
+ tv[0].tv_usec = 1234567;
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
+
+ tv[0].tv_usec = 0;
+
+ tv[1].tv_usec = -123;
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
+ tv[1].tv_usec = 1234567;
+ ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(sys_time, lutimes_nullptr) {
+ TemporaryFile tf;
+ ASSERT_EQ(0, lutimes(tf.filename, nullptr));
+}
+
+TEST(sys_time, lutimes_EINVAL) {
+ TemporaryFile tf;
+
+ timeval tv[2] = {};
+
+ tv[0].tv_usec = -123;
+ ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
+ tv[0].tv_usec = 1234567;
+ ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
+
+ tv[0].tv_usec = 0;
+
+ tv[1].tv_usec = -123;
+ ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
+ tv[1].tv_usec = 1234567;
+ ASSERT_EQ(-1, lutimes(tf.filename, tv));
+ ASSERT_EQ(EINVAL, errno);
}
TEST(sys_time, gettimeofday) {