summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorBen Smith <binji@chromium.org>2014-09-12 15:13:21 -0700
committerBen Smith <binji@chromium.org>2014-09-12 22:16:09 +0000
commit3806e82b48f9695f939db28621f9a2009bbd2a33 (patch)
tree3642ccb5bddae0aae9528d0437d13be685f6eb6c /native_client_sdk
parent84f8c167438ff802727c5a0ca2d5b56f05bb2937 (diff)
downloadchromium_src-3806e82b48f9695f939db28621f9a2009bbd2a33.zip
chromium_src-3806e82b48f9695f939db28621f9a2009bbd2a33.tar.gz
chromium_src-3806e82b48f9695f939db28621f9a2009bbd2a33.tar.bz2
[NaCl SDK] nacl_io: Plumb through {,f}utime{,s}
* Switched KernelProxy to use utimens/futimens. * kernel_intercept.* forwards utime/utimes/futimes -> {,f}utimens. * Add Node::Futimens * Override FuseFsNode::Futimens * Add newlib headers to define utime/utimes/futimes * Glibc uses at_stim as timespec instead, add define for st_atimensec for compatibility with newlib. BUG=413412 R=sbc@chromium.org Review URL: https://codereview.chromium.org/565343002 Cr-Commit-Position: refs/heads/master@{#294678}
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/libraries/nacl_io/fuse.h3
-rw-r--r--native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc14
-rw-r--r--native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/include/sys/time.h21
-rw-r--r--native_client_sdk/src/libraries/nacl_io/include/utime.h19
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc33
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc37
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/node.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/node.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ostime.h8
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/futimes.c11
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc87
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc77
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h10
19 files changed, 277 insertions, 69 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/fuse.h b/native_client_sdk/src/libraries/nacl_io/fuse.h
index 314291c..5f79786 100644
--- a/native_client_sdk/src/libraries/nacl_io/fuse.h
+++ b/native_client_sdk/src/libraries/nacl_io/fuse.h
@@ -198,6 +198,8 @@ struct fuse_operations {
size_t count,
off_t,
struct fuse_file_info*);
+ // Called by utime()/utimes()/futimes()/futimens() etc.
+ int (*utimens)(const char*, const struct timespec tv[2]);
// The following functions are not currently called by the nacl_io
// implementation of FUSE.
@@ -232,7 +234,6 @@ struct fuse_operations {
int (*setxattr)(const char*, const char*, const char*, size_t, int);
int (*statfs)(const char*, struct statvfs*);
int (*symlink)(const char*, const char*);
- int (*utimens)(const char*, const struct timespec tv[2]);
int (*write_buf)(const char*,
struct fuse_bufvec* buf,
off_t off,
diff --git a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc
index be3fe66..212f84f 100644
--- a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc
@@ -247,6 +247,20 @@ Error FuseFsNode::GetStat(struct stat* stat) {
return 0;
}
+Error FuseFsNode::Futimens(const struct timespec times[2]) {
+ int result;
+ if (!fuse_ops_->utimens) {
+ LOG_TRACE("fuse_ops_->utimens is NULL.");
+ return ENOSYS;
+ }
+
+ result = fuse_ops_->utimens(path_.c_str(), times);
+ if (result < 0)
+ return -result;
+
+ return result;
+}
+
Error FuseFsNode::VIoctl(int request, va_list args) {
LOG_ERROR("Ioctl not implemented for fusefs.");
return ENOSYS;
diff --git a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h
index 3ddc289..5bd7bc1 100644
--- a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h
@@ -54,6 +54,7 @@ class FuseFsNode : public Node {
virtual Error Tcsetattr(int optional_actions,
const struct termios* termios_p);
virtual Error GetSize(off_t* out_size);
+ virtual Error Futimens(const struct timespec times[2]);
protected:
struct fuse_operations* fuse_ops_;
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/time.h b/native_client_sdk/src/libraries/nacl_io/include/sys/time.h
new file mode 100644
index 0000000..d221d2b
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/time.h
@@ -0,0 +1,21 @@
+/* Copyright 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#ifndef LIBRARIES_NACL_IO_INCLUDE_SYS_TIME_H
+#define LIBRARIES_NACL_IO_INCLUDE_SYS_TIME_H
+
+#include <sys/cdefs.h>
+#include <stdint.h>
+#include_next <sys/time.h>
+
+__BEGIN_DECLS
+
+// TODO(binji): https://code.google.com/p/nativeclient/issues/detail?id=3949
+// remove when these declarations are added to the newlib headers.
+int utimes(const char *filename, const struct timeval times[2]);
+int futimes(int fd, const struct timeval times[2]);
+
+__END_DECLS
+
+#endif /* LIBRARIES_NACL_IO_INCLUDE_SYS_TIME_H */
diff --git a/native_client_sdk/src/libraries/nacl_io/include/utime.h b/native_client_sdk/src/libraries/nacl_io/include/utime.h
new file mode 100644
index 0000000..c3f2a54
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/utime.h
@@ -0,0 +1,19 @@
+/* Copyright 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#ifndef LIBRARIES_NACL_IO_INCLUDE_UTIME_H_
+#define LIBRARIES_NACL_IO_INCLUDE_UTIME_H_
+
+#include <sys/cdefs.h>
+#include_next <utime.h>
+
+__BEGIN_DECLS
+
+// TODO(binji): https://code.google.com/p/nativeclient/issues/detail?id=3949
+// remove when these declarations are added to the newlib headers.
+int utime(const char* filename, const struct utimbuf* times);
+
+__END_DECLS
+
+#endif /* LIBRARIES_NACL_IO_INCLUDE_UTIME_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
index 218c76fc..392f440 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -14,6 +14,7 @@
#include "nacl_io/log.h"
#include "nacl_io/osmman.h"
#include "nacl_io/ossocket.h"
+#include "nacl_io/ostime.h"
#include "nacl_io/pepper_interface.h"
#include "nacl_io/real_pepper_interface.h"
@@ -328,7 +329,24 @@ int ki_readlink(const char* path, char* buf, size_t count) {
int ki_utimes(const char* path, const struct timeval times[2]) {
ON_NOSYS_RETURN(-1);
- return s_state.kp->utimes(path, times);
+ // Implement in terms of utimens.
+ struct timespec ts[2];
+ ts[0].tv_sec = times[0].tv_sec;
+ ts[0].tv_nsec = times[0].tv_usec * 1000;
+ ts[1].tv_sec = times[1].tv_sec;
+ ts[1].tv_nsec = times[1].tv_usec * 1000;
+ return s_state.kp->utimens(path, ts);
+}
+
+int ki_futimes(int fd, const struct timeval times[2]) {
+ ON_NOSYS_RETURN(-1);
+ // Implement in terms of futimens.
+ struct timespec ts[2];
+ ts[0].tv_sec = times[0].tv_sec;
+ ts[0].tv_nsec = times[0].tv_usec * 1000;
+ ts[1].tv_sec = times[1].tv_sec;
+ ts[1].tv_nsec = times[1].tv_usec * 1000;
+ return s_state.kp->futimens(fd, ts);
}
void* ki_mmap(void* addr,
@@ -378,7 +396,18 @@ int ki_lchown(const char* path, uid_t owner, gid_t group) {
int ki_utime(const char* filename, const struct utimbuf* times) {
ON_NOSYS_RETURN(-1);
- return s_state.kp->utime(filename, times);
+ // Implement in terms of utimens.
+ struct timespec ts[2];
+ ts[0].tv_sec = times->actime;
+ ts[0].tv_nsec = 0;
+ ts[1].tv_sec = times->modtime;
+ ts[1].tv_nsec = 0;
+ return s_state.kp->utimens(filename, ts);
+}
+
+int ki_futimens(int fd, const struct timespec times[2]) {
+ ON_NOSYS_RETURN(-1);
+ return s_state.kp->futimens(fd, times);
}
int ki_poll(struct pollfd* fds, nfds_t nfds, int timeout) {
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
index aad26842..992f23c 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -107,6 +107,7 @@ int ki_symlink(const char* oldpath, const char* newpath);
int ki_access(const char* path, int amode);
int ki_readlink(const char* path, char* buf, size_t count);
int ki_utimes(const char* path, const struct timeval times[2]);
+int ki_futimes(int fd, const struct timeval times[2]);
void* ki_mmap(void* addr,
size_t length,
int prot,
@@ -121,6 +122,7 @@ int ki_chown(const char* path, uid_t owner, gid_t group);
int ki_fchown(int fd, uid_t owner, gid_t group);
int ki_lchown(const char* path, uid_t owner, gid_t group);
int ki_utime(const char* filename, const struct utimbuf* times);
+int ki_futimens(int fd, const struct timespec times[2]);
int ki_poll(struct pollfd* fds, nfds_t nfds, int timeout);
int ki_select(int nfds,
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index 20d78f2..cf6cf07 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -324,7 +324,7 @@ char* KernelProxy::getwd(char* buf) {
}
int KernelProxy::chmod(const char* path, mode_t mode) {
- int fd = KernelProxy::open(path, O_RDONLY, mode);
+ int fd = open(path, O_RDONLY, mode);
if (-1 == fd)
return -1;
@@ -345,10 +345,6 @@ int KernelProxy::lchown(const char* path, uid_t owner, gid_t group) {
return 0;
}
-int KernelProxy::utime(const char* filename, const struct utimbuf* times) {
- return 0;
-}
-
int KernelProxy::mkdir(const char* path, mode_t mode) {
ScopedFilesystem fs;
Path rel;
@@ -680,6 +676,23 @@ int KernelProxy::ioctl(int fd, int request, va_list args) {
return 0;
}
+int KernelProxy::futimens(int fd, const struct timespec times[2]) {
+ ScopedKernelHandle handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ error = handle->node()->Futimens(times);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ return 0;
+}
+
off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
@@ -718,7 +731,7 @@ int KernelProxy::unlink(const char* path) {
}
int KernelProxy::truncate(const char* path, off_t len) {
- int fd = KernelProxy::open(path, O_WRONLY, 0);
+ int fd = open(path, O_WRONLY, 0);
if (-1 == fd)
return -1;
@@ -864,10 +877,14 @@ int KernelProxy::readlink(const char* path, char* buf, size_t count) {
return -1;
}
-int KernelProxy::utimes(const char* filename, const struct timeval times[2]) {
- LOG_TRACE("utimes is not implemented.");
- errno = EINVAL;
- return -1;
+int KernelProxy::utimens(const char* path, const struct timespec times[2]) {
+ int fd = open(path, O_RDONLY, 0);
+ if (-1 == fd)
+ return -1;
+
+ int result = futimens(fd, times);
+ close(fd);
+ return result;
}
// TODO(noelallen): Needs implementation.
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
index 0cfdbff..fb11288 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -89,7 +89,6 @@ class KernelProxy : protected KernelObject {
virtual int chown(const char* path, uid_t owner, gid_t group);
virtual int fchown(int fd, uid_t owner, gid_t group);
virtual int lchown(const char* path, uid_t owner, gid_t group);
- virtual int utime(const char* filename, const struct utimbuf* times);
// System calls that take a path as an argument: The kernel proxy will look
// for the Node associated to the path. To find the node, the kernel proxy
@@ -118,6 +117,7 @@ class KernelProxy : protected KernelObject {
virtual int fdatasync(int fd);
virtual int isatty(int fd);
virtual int ioctl(int fd, int request, va_list args);
+ virtual int futimens(int fd, const struct timespec times[2]);
// lseek() relies on the filesystem's Stat() to determine whether or not the
// file handle corresponding to fd is a directory
@@ -135,7 +135,7 @@ class KernelProxy : protected KernelObject {
// access() uses the Filesystem's Stat().
virtual int access(const char* path, int amode);
virtual int readlink(const char* path, char* buf, size_t count);
- virtual int utimes(const char* filename, const struct timeval times[2]);
+ virtual int utimens(const char* path, const struct timespec times[2]);
virtual int link(const char* oldpath, const char* newpath);
virtual int symlink(const char* oldpath, const char* newpath);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
index ee7bf373d..b606367 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
@@ -116,7 +116,7 @@ extern int stat(const char* path, struct stat* buf) NOTHROW;
int symlink(const char* oldpath, const char* newpath) NOTHROW;
int umount(const char* path) NOTHROW;
int NAME(unlink)(const char* path) NOTHROW;
-int utime(const char* filename, const struct utimbuf* times);
+int utime(const char* filename, const struct utimbuf* times) NOTHROW;
read_ssize_t NAME(write)(int fd, const void* buf, size_t nbyte);
#ifdef PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
index 58fa1c1..a264eeb 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -25,6 +25,7 @@
#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/log.h"
#include "nacl_io/osmman.h"
+#include "nacl_io/ostime.h"
namespace {
@@ -41,8 +42,11 @@ void stat_to_nacl_stat(const struct stat* buf, nacl_abi_stat* nacl_buf) {
nacl_buf->nacl_abi_st_blksize = buf->st_blksize;
nacl_buf->nacl_abi_st_blocks = buf->st_blocks;
nacl_buf->nacl_abi_st_atime = buf->st_atime;
+ nacl_buf->nacl_abi_st_atimensec = buf->st_atimensec;
nacl_buf->nacl_abi_st_mtime = buf->st_mtime;
+ nacl_buf->nacl_abi_st_mtimensec = buf->st_mtimensec;
nacl_buf->nacl_abi_st_ctime = buf->st_ctime;
+ nacl_buf->nacl_abi_st_ctimensec = buf->st_ctimensec;
}
void nacl_stat_to_stat(const nacl_abi_stat* nacl_buf, struct stat* buf) {
@@ -58,8 +62,11 @@ void nacl_stat_to_stat(const nacl_abi_stat* nacl_buf, struct stat* buf) {
buf->st_blksize = nacl_buf->nacl_abi_st_blksize;
buf->st_blocks = nacl_buf->nacl_abi_st_blocks;
buf->st_atime = nacl_buf->nacl_abi_st_atime;
+ buf->st_atimensec = nacl_buf->nacl_abi_st_atimensec;
buf->st_mtime = nacl_buf->nacl_abi_st_mtime;
+ buf->st_mtimensec = nacl_buf->nacl_abi_st_mtimensec;
buf->st_ctime = nacl_buf->nacl_abi_st_ctime;
+ buf->st_ctimensec = nacl_buf->nacl_abi_st_ctimensec;
}
} // namespace
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index f3f64c8..9493dfb 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -75,6 +75,7 @@
"syscalls/fchown.c",
"syscalls/fcntl.c",
"syscalls/ftruncate.c",
+ "syscalls/futimes.c",
"syscalls/getcwd.c",
"syscalls/getwd.c",
"syscalls/ioctl.c",
@@ -232,7 +233,9 @@
"sys/signal.h",
"sys/socket.h",
"sys/termios.h",
+ "sys/time.h",
"sys/utsname.h",
+ "utime.h",
],
'DEST': 'include/newlib',
},
@@ -251,7 +254,9 @@
"sys/select.h",
"sys/socket.h",
"sys/termios.h",
+ "sys/time.h",
"sys/utsname.h",
+ "utime.h",
],
'DEST': 'include/pnacl',
},
diff --git a/native_client_sdk/src/libraries/nacl_io/node.cc b/native_client_sdk/src/libraries/nacl_io/node.cc
index a097708..76d3734 100644
--- a/native_client_sdk/src/libraries/nacl_io/node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/node.cc
@@ -176,6 +176,10 @@ Error Node::Tcsetattr(int optional_actions, const struct termios* termios_p) {
return EINVAL;
}
+Error Node::Futimens(const struct timespec times[2]) {
+ return EINVAL;
+}
+
int Node::GetLinks() {
return stat_.st_nlink;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/node.h b/native_client_sdk/src/libraries/nacl_io/node.h
index 0b42e29..c30c796 100644
--- a/native_client_sdk/src/libraries/nacl_io/node.h
+++ b/native_client_sdk/src/libraries/nacl_io/node.h
@@ -89,6 +89,7 @@ class Node : public sdk_util::RefObject {
virtual Error Tcgetattr(struct termios* termios_p);
virtual Error Tcsetattr(int optional_actions,
const struct termios* termios_p);
+ virtual Error Futimens(const struct timespec times[2]);
virtual int GetLinks();
virtual int GetMode();
diff --git a/native_client_sdk/src/libraries/nacl_io/ostime.h b/native_client_sdk/src/libraries/nacl_io/ostime.h
index d3b52a5..e48ef22 100644
--- a/native_client_sdk/src/libraries/nacl_io/ostime.h
+++ b/native_client_sdk/src/libraries/nacl_io/ostime.h
@@ -19,6 +19,14 @@ int clock_settime(clockid_t clock_id, const struct timespec* tp);
#else
#include <time.h>
+#include <utime.h>
+#include <sys/time.h>
+
+#ifdef __GLIBC__
+#define st_atimensec st_atim.tv_nsec
+#define st_mtimensec st_mtim.tv_nsec
+#define st_ctimensec st_ctim.tv_nsec
+#endif
#endif
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/futimes.c b/native_client_sdk/src/libraries/nacl_io/syscalls/futimes.c
new file mode 100644
index 0000000..811474e
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/futimes.c
@@ -0,0 +1,11 @@
+/* Copyright (c) 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int futimes(int fd, const struct timeval times[2]) {
+ return ki_futimes(fd, times);
+}
+
diff --git a/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc b/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc
index bf4b51d..dffc1ba 100644
--- a/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc
@@ -14,6 +14,7 @@
#include "nacl_io/kernel_handle.h"
#include "nacl_io/kernel_intercept.h"
#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/ostime.h"
using namespace nacl_io;
@@ -30,8 +31,13 @@ class FuseFsForTesting : public FuseFs {
// Implementation of a simple flat memory filesystem.
struct File {
+ File() {
+ memset(&times, 0, sizeof(times));
+ }
+
std::string name;
std::vector<uint8_t> data;
+ timespec times[2];
};
typedef std::vector<File> Files;
@@ -77,6 +83,10 @@ int testfs_getattr(const char* path, struct stat* stbuf) {
stbuf->st_mode = S_IFREG | last_create_mode;
stbuf->st_size = file->data.size();
+ stbuf->st_atime = file->times[0].tv_sec;
+ stbuf->st_atimensec = file->times[0].tv_nsec;
+ stbuf->st_mtime = file->times[1].tv_sec;
+ stbuf->st_mtimensec = file->times[1].tv_nsec;
return 0;
}
@@ -160,32 +170,43 @@ int testfs_write(const char* path,
return size;
}
+int testfs_utimens(const char* path, const struct timespec times[2]) {
+ File* file = FindFile(path);
+ if (file == NULL)
+ return -ENOENT;
+
+ file->times[0] = times[0];
+ file->times[1] = times[1];
+ return 0;
+}
+
const char hello_world[] = "Hello, World!\n";
fuse_operations g_fuse_operations = {
- 0, // flag_nopath
- 0, // flag_reserved
- NULL, // init
- NULL, // destroy
- NULL, // access
- testfs_create, // create
- NULL, // fgetattr
- NULL, // fsync
- NULL, // ftruncate
- testfs_getattr, // getattr
- NULL, // mkdir
- NULL, // mknod
- testfs_open, // open
- NULL, // opendir
- testfs_read, // read
- testfs_readdir, // readdir
- NULL, // release
- NULL, // releasedir
- NULL, // rename
- NULL, // rmdir
- NULL, // truncate
- NULL, // unlink
- testfs_write, // write
+ 0, // flag_nopath
+ 0, // flag_reserved
+ NULL, // init
+ NULL, // destroy
+ NULL, // access
+ testfs_create, // create
+ NULL, // fgetattr
+ NULL, // fsync
+ NULL, // ftruncate
+ testfs_getattr, // getattr
+ NULL, // mkdir
+ NULL, // mknod
+ testfs_open, // open
+ NULL, // opendir
+ testfs_read, // read
+ testfs_readdir, // readdir
+ NULL, // release
+ NULL, // releasedir
+ NULL, // rename
+ NULL, // rmdir
+ NULL, // truncate
+ NULL, // unlink
+ testfs_write, // write
+ testfs_utimens, // utimens
};
class FuseFsTest : public ::testing::Test {
@@ -320,6 +341,26 @@ TEST_F(FuseFsTest, GetDents) {
EXPECT_STREQ("foobar", entries[3].d_name);
}
+TEST_F(FuseFsTest, Utimens) {
+ struct stat statbuf;
+ ScopedNode node;
+
+ struct timespec times[2];
+ times[0].tv_sec = 1000;
+ times[0].tv_nsec = 2000;
+ times[1].tv_sec = 3000;
+ times[1].tv_nsec = 4000;
+
+ ASSERT_EQ(0, fs_.Open(Path("/hello"), O_RDONLY, &node));
+ EXPECT_EQ(0, node->Futimens(times));
+
+ EXPECT_EQ(0, node->GetStat(&statbuf));
+ EXPECT_EQ(times[0].tv_sec, statbuf.st_atime);
+ EXPECT_EQ(times[0].tv_nsec, statbuf.st_atimensec);
+ EXPECT_EQ(times[1].tv_sec, statbuf.st_mtime);
+ EXPECT_EQ(times[1].tv_nsec, statbuf.st_mtimensec);
+}
+
namespace {
class KernelProxyFuseTest : public ::testing::Test {
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc
index 79446ae..00f2e44 100644
--- a/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc
@@ -19,13 +19,13 @@
#include "nacl_io/osmman.h"
#include "nacl_io/ossocket.h"
#include "nacl_io/ostermios.h"
+#include "nacl_io/ostime.h"
#include "ppapi_simple/ps.h"
#if defined(__native_client__) && !defined(__GLIBC__)
extern "C" {
-// TODO(sbc): remove once these get added to the newlib toolchain headers.
+// TODO(sbc): remove once this gets added to the newlib toolchain headers.
int fchdir(int fd);
-int utimes(const char *filename, const struct timeval times[2]);
}
#endif
@@ -40,30 +40,48 @@ using ::testing::StrEq;
namespace {
-#define COMPARE_FIELD(f) \
- if (arg->f != statbuf->f) { \
- *result_listener << "mismatch of field \"" #f \
- "\". " \
- "expected: " << statbuf->f << " actual: " << arg->f; \
- return false; \
+#define COMPARE_FIELD(actual, expected, f) \
+ if (actual != expected) { \
+ *result_listener << "mismatch of field \"" f \
+ "\". " \
+ "expected: " << expected << " actual: " << actual; \
+ return false; \
}
-MATCHER_P(IsEqualToStatbuf, statbuf, "") {
- COMPARE_FIELD(st_dev);
- COMPARE_FIELD(st_ino);
- COMPARE_FIELD(st_mode);
- COMPARE_FIELD(st_nlink);
- COMPARE_FIELD(st_uid);
- COMPARE_FIELD(st_gid);
- COMPARE_FIELD(st_rdev);
- COMPARE_FIELD(st_size);
- COMPARE_FIELD(st_atime);
- COMPARE_FIELD(st_mtime);
- COMPARE_FIELD(st_ctime);
+#define COMPARE_FIELD_SIMPLE(f) COMPARE_FIELD(arg->f, other->f, #f)
+
+MATCHER_P(IsEqualToStatbuf, other, "") {
+ COMPARE_FIELD_SIMPLE(st_dev);
+ COMPARE_FIELD_SIMPLE(st_ino);
+ COMPARE_FIELD_SIMPLE(st_mode);
+ COMPARE_FIELD_SIMPLE(st_nlink);
+ COMPARE_FIELD_SIMPLE(st_uid);
+ COMPARE_FIELD_SIMPLE(st_gid);
+ COMPARE_FIELD_SIMPLE(st_rdev);
+ COMPARE_FIELD_SIMPLE(st_size);
+ COMPARE_FIELD_SIMPLE(st_atime);
+ COMPARE_FIELD_SIMPLE(st_mtime);
+ COMPARE_FIELD_SIMPLE(st_ctime);
+ return true;
+}
+
+MATCHER_P(IsEqualToUtimbuf, other, "") {
+ COMPARE_FIELD(arg[0].tv_sec, other->actime, "actime");
+ COMPARE_FIELD(arg[1].tv_sec, other->modtime, "modtime");
+ return true;
+}
+
+MATCHER_P(IsEqualToTimeval, other, "") {
+ COMPARE_FIELD(arg[0].tv_sec, other[0].tv_sec, "[0].tv_sec");
+ COMPARE_FIELD(arg[0].tv_nsec, other[0].tv_usec * 1000, "[0].tv_usec");
+ COMPARE_FIELD(arg[1].tv_sec, other[1].tv_sec, "[1].tv_sec");
+ COMPARE_FIELD(arg[1].tv_nsec, other[1].tv_usec * 1000, "[1].tv_usec");
return true;
}
#undef COMPARE_FIELD
+#undef COMPARE_FIELD_SIMPLE
+
ACTION_P(SetErrno, value) {
errno = value;
@@ -302,6 +320,14 @@ TEST_F(KernelWrapTest, fsync) {
ASSERT_EQ(kDummyErrno, errno);
}
+TEST_F(KernelWrapTest, futimes) {
+ struct timeval times[2] = {{123, 234}, {345, 456}};
+ EXPECT_CALL(mock, futimens(kDummyInt, IsEqualToTimeval(times)))
+ .WillOnce(DoAll(SetErrno(kDummyErrno), Return(-1)));
+ EXPECT_EQ(-1, futimes(kDummyInt, times));
+ ASSERT_EQ(kDummyErrno, errno);
+}
+
TEST_F(KernelWrapTest, getcwd) {
char buffer[PATH_MAX];
char result[PATH_MAX];
@@ -615,14 +641,15 @@ TEST_F(KernelWrapTest, unlink) {
}
TEST_F(KernelWrapTest, utime) {
- const struct utimbuf* times = NULL;
- EXPECT_CALL(mock, utime(kDummyConstChar, times)).WillOnce(Return(kDummyInt));
- EXPECT_EQ(kDummyInt, utime(kDummyConstChar, times));
+ const struct utimbuf times = {123, 456};
+ EXPECT_CALL(mock, utimens(kDummyConstChar, IsEqualToUtimbuf(&times)))
+ .WillOnce(Return(kDummyInt));
+ EXPECT_EQ(kDummyInt, utime(kDummyConstChar, &times));
}
TEST_F(KernelWrapTest, utimes) {
- struct timeval* times = NULL;
- EXPECT_CALL(mock, utimes(kDummyConstChar, times))
+ struct timeval times[2] = {{123, 234}, {345, 456}};
+ EXPECT_CALL(mock, utimens(kDummyConstChar, IsEqualToTimeval(times)))
.WillOnce(DoAll(SetErrno(kDummyErrno), Return(-1)));
EXPECT_EQ(-1, utimes(kDummyConstChar, times));
ASSERT_EQ(kDummyErrno, errno);
diff --git a/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h b/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h
index 04a37af..b29fe6a 100644
--- a/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h
+++ b/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h
@@ -29,10 +29,11 @@ class MockKernelProxy : public nacl_io::KernelProxy {
MOCK_METHOD2(fchmod, int(int, int));
MOCK_METHOD3(fchown, int(int, uid_t, gid_t));
MOCK_METHOD3(fcntl, int(int, int, va_list));
+ MOCK_METHOD1(fdatasync, int(int));
MOCK_METHOD2(ftruncate, int(int, off_t));
MOCK_METHOD2(fstat, int(int, struct stat*));
MOCK_METHOD1(fsync, int(int));
- MOCK_METHOD1(fdatasync, int(int));
+ MOCK_METHOD2(futimens, int(int, const struct timespec[2]));
MOCK_METHOD2(getcwd, char*(char*, size_t));
MOCK_METHOD3(getdents, int(int, void*, unsigned int));
MOCK_METHOD1(getwd, char*(char*));
@@ -49,6 +50,7 @@ class MockKernelProxy : public nacl_io::KernelProxy {
const void*));
MOCK_METHOD2(munmap, int(void*, size_t));
MOCK_METHOD3(open, int(const char*, int, mode_t));
+ MOCK_METHOD1(open_resource, int(const char*));
MOCK_METHOD1(pipe, int(int[2]));
MOCK_METHOD3(read, ssize_t(int, void*, size_t));
MOCK_METHOD3(readlink, int(const char*, char*, size_t count));
@@ -61,13 +63,11 @@ class MockKernelProxy : public nacl_io::KernelProxy {
MOCK_METHOD2(tcflush, int(int, int));
MOCK_METHOD2(tcgetattr, int(int, struct termios*));
MOCK_METHOD3(tcsetattr, int(int, int, const struct termios*));
- MOCK_METHOD1(umount, int(const char*));
MOCK_METHOD2(truncate, int(const char*, off_t));
+ MOCK_METHOD1(umount, int(const char*));
MOCK_METHOD1(unlink, int(const char*));
- MOCK_METHOD2(utime, int(const char*, const struct utimbuf*));
- MOCK_METHOD2(utimes, int(const char*, const struct timeval[2]));
+ MOCK_METHOD2(utimens, int(const char*, const struct timespec[2]));
MOCK_METHOD3(write, ssize_t(int, const void*, size_t));
- MOCK_METHOD1(open_resource, int(const char*));
#ifdef PROVIDES_SOCKET_API
MOCK_METHOD3(poll, int(struct pollfd*, nfds_t, int));