diff options
author | Ben Smith <binji@chromium.org> | 2014-09-12 15:13:21 -0700 |
---|---|---|
committer | Ben Smith <binji@chromium.org> | 2014-09-12 22:16:09 +0000 |
commit | 3806e82b48f9695f939db28621f9a2009bbd2a33 (patch) | |
tree | 3642ccb5bddae0aae9528d0437d13be685f6eb6c /native_client_sdk | |
parent | 84f8c167438ff802727c5a0ca2d5b56f05bb2937 (diff) | |
download | chromium_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')
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(×, 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(×))) + .WillOnce(Return(kDummyInt)); + EXPECT_EQ(kDummyInt, utime(kDummyConstChar, ×)); } 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)); |