| Index: tests/syscalls/syscalls.cc
|
| diff --git a/tests/syscalls/syscalls.cc b/tests/syscalls/syscalls.cc
|
| index 30bd61855efdfd554bd7c8aea089f2d64a882b13..e063c109e9a83f3326a36e30c2fc12980dcbb07d 100644
|
| --- a/tests/syscalls/syscalls.cc
|
| +++ b/tests/syscalls/syscalls.cc
|
| @@ -18,14 +18,17 @@
|
| #include <string.h>
|
| #include <sys/stat.h>
|
| #include <unistd.h>
|
| -#include <utime.h>
|
|
|
| +#include "native_client/src/include/build_config.h"
|
| #include "native_client/src/include/nacl_assert.h"
|
| #include "native_client/src/trusted/service_runtime/nacl_config.h"
|
| +#include "native_client/src/untrusted/nacl/syscall_bindings_trampoline.h"
|
|
|
| #define PRINT_HEADER 0
|
| #define TEXT_LINE_SIZE 1024
|
|
|
| +bool windows = false;
|
| +
|
| /*
|
| * TODO(sbc): remove this test once these declarations get added to the
|
| * newlib toolchain
|
| @@ -33,8 +36,6 @@
|
| #ifndef __GLIBC__
|
| extern "C" {
|
| int gethostname(char *name, size_t len);
|
| -int utimes(const char *filename, const struct timeval times[2]);
|
| -int utime(const char *filename, const struct utimbuf *times);
|
| int eaccess(const char *pathname, int mode);
|
| }
|
| #endif
|
| @@ -137,8 +138,66 @@ bool test_chdir() {
|
| return passed("test_chdir", "all");
|
| }
|
|
|
| +bool test_fchdir() {
|
| + char dirname[PATH_MAX] = { '\0' };
|
| + char newdir[PATH_MAX] = { '\0' };
|
| + char parent[PATH_MAX] = { '\0' };
|
| + int retcode;
|
| + int fd;
|
| + char *rtn = getcwd(dirname, PATH_MAX);
|
| + ASSERT_EQ_MSG(rtn, dirname, "getcwd() failed");
|
| +
|
| + // Calculate parent folder.
|
| + strncpy(parent, dirname, PATH_MAX);
|
| + char *basename_start;
|
| + if (windows) {
|
| + basename_start = strrchr(parent, '\\');
|
| + } else {
|
| + basename_start = strrchr(parent, '/');
|
| + }
|
| +
|
| + if (basename_start == NULL) {
|
| + basename_start = strrchr(parent, '\\');
|
| + ASSERT_NE_MSG(basename_start, NULL, "test_file contains no dir seperator");
|
| + }
|
| + basename_start[0] = '\0';
|
| +
|
| + // Open parent folder
|
| + fd = open(parent, O_RDONLY | O_DIRECTORY);
|
| + ASSERT_NE_MSG(fd, -1, "open() failed to open parent directory");
|
| +
|
| + retcode = NACL_SYSCALL(fchdir)(fd);
|
| + if (windows) {
|
| + // TODO(smklein) Update this once fchdir is implemented.
|
| + ASSERT_NE_MSG(retcode, 0, "fchdir() should have failed");
|
| + return passed("test_fchdir", "all");
|
| + } else {
|
| + ASSERT_EQ_MSG(retcode, 0, "fchdir() failed");
|
| + }
|
| +
|
| + rtn = getcwd(newdir, PATH_MAX);
|
| + ASSERT_EQ_MSG(rtn, newdir, "getcwd() failed");
|
| +
|
| + ASSERT_MSG(strcmp(newdir, parent) == 0, "getcwd() failed after fchdir");
|
| +
|
| + ASSERT_EQ_MSG(close(fd), 0, "close() failed");
|
| +
|
| + // Let's go back to the child directory
|
| + fd = open(dirname, O_RDONLY | O_DIRECTORY);
|
| + ASSERT_NE_MSG(fd, -1, "open() failed to open child directory");
|
| +
|
| + retcode = NACL_SYSCALL(fchdir)(fd);
|
| + ASSERT_EQ_MSG(retcode, 0, "fchdir() failed");
|
| +
|
| + rtn = getcwd(newdir, PATH_MAX);
|
| + ASSERT_EQ_MSG(rtn, newdir, "getcwd() failed");
|
| +
|
| + ASSERT_MSG(strcmp(newdir, dirname) == 0, "getcwd() failed after fchdir");
|
| + return passed("test fchdir", "all");
|
| +}
|
| +
|
| bool test_mkdir_rmdir(const char *test_file) {
|
| - // Use a temporary direcotry name alongside the test_file which
|
| + // Use a temporary directory name alongside the test_file which
|
| // was passed in.
|
| char dirname[PATH_MAX];
|
| strncpy(dirname, test_file, PATH_MAX);
|
| @@ -309,7 +368,7 @@ bool test_link(const char *test_file) {
|
| ASSERT_EQ(close(fd), 0);
|
|
|
| int rtn = link(target_filename, link_filename);
|
| - if (rtn != 0 && errno == ENOSYS) {
|
| + if (rtn != 0 && errno == ENOSYS && windows) {
|
| // If we get ENOSYS, assume we are on Windows, where link() is expected
|
| // to fail.
|
| return passed("test_link", "all");
|
| @@ -365,7 +424,7 @@ bool test_symlinks(const char *test_file) {
|
|
|
| // Create this link
|
| int rtn = symlink(basename, link_filename);
|
| - if (rtn != 0 && errno == ENOSYS) {
|
| + if (rtn != 0 && errno == ENOSYS && windows) {
|
| // If we get ENOSYS, assume we are on Windows, where symlink() and
|
| // readlink() are expected to fail.
|
| return passed("test_symlinks", "all");
|
| @@ -429,6 +488,36 @@ bool test_chmod(const char *test_file) {
|
| return passed("test_chmod", "all");
|
| }
|
|
|
| +bool test_fchmod(const char *test_file) {
|
| + struct stat buf;
|
| + char temp_file[PATH_MAX];
|
| + int retcode;
|
| + snprintf(temp_file, PATH_MAX, "%s.tmp_fchmod", test_file);
|
| +
|
| + int fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
| + ASSERT(fd >= 0);
|
| +
|
| + ASSERT_EQ(stat(temp_file, &buf), 0);
|
| + ASSERT_EQ(buf.st_mode & ~S_IFMT, S_IRUSR | S_IWUSR);
|
| +
|
| + // change the file to readonly and verify the change
|
| + retcode = NACL_SYSCALL(fchmod)(fd, S_IRUSR);
|
| + if (windows) {
|
| + // TODO(smklein) Update this once fchmod is implemented.
|
| + ASSERT_NE_MSG(retcode, 0, "fchmod() should have failed");
|
| + return passed("test_fchmod", "all");
|
| + } else {
|
| + ASSERT_EQ(retcode, 0);
|
| + }
|
| + ASSERT_EQ(stat(temp_file, &buf), 0);
|
| + ASSERT_EQ(buf.st_mode & ~S_IFMT, S_IRUSR);
|
| + ASSERT(open(temp_file, O_WRONLY) < 0);
|
| +
|
| + ASSERT_EQ(close(fd), 0);
|
| + ASSERT_EQ(remove(temp_file), 0);
|
| + return passed("test_fchmod", "all");
|
| +}
|
| +
|
| static void test_access_call(const char *path, int mode, int expected_result) {
|
| ASSERT_EQ(access(path, mode), expected_result);
|
| ASSERT_EQ(eaccess(path, mode), expected_result);
|
| @@ -472,28 +561,76 @@ bool test_utimes(const char *test_file) {
|
| if (NONSFI_MODE)
|
| return true;
|
| struct timeval times[2];
|
| - // utimes() is currently not implemented and should always
|
| - // fail with ENOSYS
|
| - ASSERT_EQ(utimes("dummy", times), -1);
|
| - ASSERT_EQ(errno, ENOSYS);
|
| + // These numbers are close enough to the epoch time. Windows
|
| + // does not like going back in time.
|
| + time_t a_sec = 2132067496;
|
| + time_t m_sec = 2132067497;
|
| + times[0].tv_sec = a_sec;
|
| + times[0].tv_usec = 222;
|
| + times[1].tv_sec = m_sec;
|
| + times[1].tv_usec = 444;
|
| + char temp_file[PATH_MAX];
|
| + snprintf(temp_file, PATH_MAX, "%s.tmp_utimes", test_file);
|
| + ensure_file_is_absent(temp_file);
|
| +
|
| + int fd = open(temp_file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
|
| + ASSERT(fd >= 0);
|
| + ASSERT_EQ(close(fd), 0);
|
| +
|
| + // Use the times we generated earlier (and check the second resolution)
|
| + ASSERT_EQ(NACL_SYSCALL(utimes)(temp_file, times), 0);
|
| +
|
| + // Verify the actime + modtime.
|
| + struct stat s;
|
| + ASSERT_EQ(stat(temp_file, &s), 0);
|
| + ASSERT_EQ(s.st_atime, a_sec);
|
| + ASSERT_EQ(s.st_mtime, m_sec);
|
| +
|
| + // "NULL" should be a valid time. We only check error code status here.
|
| + ASSERT_EQ(NACL_SYSCALL(utimes)(temp_file, NULL), 0);
|
| return passed("test_utimes", "all");
|
| }
|
|
|
| -bool test_utime(const char *test_file) {
|
| - // TODO(mseaborn): Implement utimes for unsandboxed mode.
|
| - if (NONSFI_MODE)
|
| - return true;
|
| - printf("test_utime");
|
| - struct utimbuf times;
|
| - times.actime = 0;
|
| - times.modtime = 0;
|
| - // utimes() is currently not implemented and should always
|
| - // fail with ENOSYS
|
| - printf("test_utime 2");
|
| -
|
| - ASSERT_EQ(utime("dummy", ×), -1);
|
| - ASSERT_EQ(errno, ENOSYS);
|
| - return passed("test_utime", "all");
|
| +bool test_fsync(const char *test_file) {
|
| + char temp_file[PATH_MAX];
|
| + snprintf(temp_file, PATH_MAX, "%s.tmp_fsync", test_file);
|
| +
|
| + char buffer[100];
|
| + for (size_t i = 0; i < sizeof(buffer); i++)
|
| + buffer[i] = i;
|
| +
|
| + // Write 100 sequential chars to the test file.
|
| + int fd = open(temp_file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
|
| + ASSERT(fd >= 0);
|
| + ASSERT_EQ(100, write(fd, buffer, 100));
|
| +
|
| + // For now, only testing that fsync does not return an error.
|
| + // This is a weak test -- TODO(smklein) improve it.
|
| + ASSERT_EQ(0, NACL_SYSCALL(fsync)(fd));
|
| + ASSERT_EQ(0, close(fd));
|
| +
|
| + return passed("test_fsync", "all");
|
| +}
|
| +
|
| +bool test_fdatasync(const char *test_file) {
|
| + char temp_file[PATH_MAX];
|
| + snprintf(temp_file, PATH_MAX, "%s.tmp_fdatasync", test_file);
|
| +
|
| + char buffer[100];
|
| + for (size_t i = 0; i < sizeof(buffer); i++)
|
| + buffer[i] = i;
|
| +
|
| + // Write 100 sequential chars to the test file.
|
| + int fd = open(temp_file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
|
| + ASSERT(fd >= 0);
|
| + ASSERT_EQ(100, write(fd, buffer, 100));
|
| +
|
| + // For now, only testing that fdatasync does not return an error.
|
| + // This is a weak test -- TODO(smklein) improve it.
|
| + ASSERT_EQ(0, NACL_SYSCALL(fdatasync)(fd));
|
| + ASSERT_EQ(0, close(fd));
|
| +
|
| + return passed("test_fdatasync", "all");
|
| }
|
|
|
| bool test_truncate(const char *test_file) {
|
| @@ -546,6 +683,59 @@ bool test_truncate(const char *test_file) {
|
| return passed("test_truncate", "all");
|
| }
|
|
|
| +bool test_ftruncate(const char *test_file) {
|
| + char temp_file[PATH_MAX];
|
| + snprintf(temp_file, PATH_MAX, "%s.tmp_ftruncate", test_file);
|
| +
|
| + char buffer[100];
|
| + char read_buffer[200];
|
| + struct stat buf;
|
| + for (size_t i = 0; i < sizeof(buffer); i++)
|
| + buffer[i] = i;
|
| +
|
| + // Write 100 sequential chars to the test file.
|
| + int fd = open(temp_file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
|
| + ASSERT(fd >= 0);
|
| + ASSERT_EQ(100, write(fd, buffer, 100));
|
| +
|
| + ASSERT_EQ(0, close(fd));
|
| + fd = open(temp_file, O_WRONLY, S_IRUSR | S_IWUSR);
|
| + ASSERT_EQ(stat(temp_file, &buf), 0);
|
| + ASSERT_EQ(buf.st_size, 100);
|
| +
|
| + // ftruncate the file beyond its current length
|
| + ASSERT_EQ(NACL_SYSCALL(ftruncate)(fd, 200), 0);
|
| + ASSERT_EQ(0, close(fd));
|
| + ASSERT_EQ(stat(temp_file, &buf), 0);
|
| + ASSERT_EQ(buf.st_size, 200);
|
| +
|
| + // Verify the new content, which should not be 100
|
| + // bytes of sequential chars and 100 bytes of '\0'
|
| + fd = open(temp_file, O_RDWR);
|
| + ASSERT(fd >= 0);
|
| + ASSERT_EQ(read(fd, read_buffer, 200), 200);
|
| + ASSERT_EQ(memcmp(read_buffer, buffer, 100), 0);
|
| + for (int i = 100; i < 200; i++)
|
| + ASSERT_EQ(read_buffer[i], 0);
|
| +
|
| + // Now ftruncate the file to a size smaller than the
|
| + // original
|
| + ASSERT_EQ(NACL_SYSCALL(ftruncate)(fd, 50), 0);
|
| + ASSERT_EQ(0, close(fd));
|
| + ASSERT_EQ(stat(temp_file, &buf), 0);
|
| + ASSERT_EQ(buf.st_size, 50);
|
| +
|
| + fd = open(temp_file, O_RDONLY);
|
| + ASSERT(fd >= 0);
|
| + ASSERT_EQ(read(fd, read_buffer, 50), 50);
|
| + ASSERT_EQ(memcmp(read_buffer, buffer, 50), 0);
|
| + ASSERT_EQ(0, close(fd));
|
| +
|
| + ASSERT_EQ(remove(temp_file), 0);
|
| + return passed("test_ftruncate", "all");
|
| +}
|
| +
|
| +
|
| bool test_open_trunc(const char *test_file) {
|
| int fd;
|
| char buffer[100];
|
| @@ -1176,7 +1366,7 @@ bool testSuite(const char *test_file) {
|
| #if !defined(__GLIBC__) || TESTS_USE_IRT
|
| ret &= test_unlink(test_file);
|
| ret &= test_chdir();
|
| - ret &= test_mkdir_rmdir(test_file);
|
| + ret &= test_fchdir();
|
| ret &= test_getcwd();
|
| ret &= test_mkdir_rmdir(test_file);
|
| ret &= test_isatty(test_file);
|
| @@ -1184,16 +1374,19 @@ bool testSuite(const char *test_file) {
|
| ret &= test_link(test_file);
|
| ret &= test_symlinks(test_file);
|
| ret &= test_chmod(test_file);
|
| + ret &= test_fchmod(test_file);
|
| ret &= test_access(test_file);
|
| + ret &= test_fsync(test_file);
|
| + ret &= test_fdatasync(test_file);
|
| + ret &= test_utimes(test_file);
|
| #endif
|
| // TODO(sbc): remove this restriction once glibc's truncate calls
|
| // is hooked up to the IRT dev-filename-0.2 interface:
|
| // https://code.google.com/p/nativeclient/issues/detail?id=3709
|
| #if !(defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 9)
|
| ret &= test_truncate(test_file);
|
| + ret &= test_ftruncate(test_file);
|
| #endif
|
| - ret &= test_utimes(test_file);
|
| - ret &= test_utime(test_file);
|
| return ret;
|
| }
|
|
|
| @@ -1208,10 +1401,13 @@ bool testSuite(const char *test_file) {
|
| int main(const int argc, const char *argv[]) {
|
| bool passed;
|
|
|
| - if (argc != 2) {
|
| + if (argc != 3) {
|
| printf("Please specify the test file name\n");
|
| exit(-1);
|
| }
|
| + if (argv[2][0] == 'w') {
|
| + windows = true;
|
| + }
|
| // run the full test suite
|
| passed = testSuite(argv[1]);
|
|
|
|
|