Home | History | Annotate | Download | only in nacl_io_test
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <errno.h>
      6 #include <fcntl.h>
      7 #include <pthread.h>
      8 #include <stdio.h>
      9 #include <sys/stat.h>
     10 
     11 #include <map>
     12 #include <string>
     13 
     14 #include "gmock/gmock.h"
     15 #include "gtest/gtest.h"
     16 
     17 #include "mock_fs.h"
     18 #include "mock_node.h"
     19 
     20 #include "nacl_io/filesystem.h"
     21 #include "nacl_io/kernel_intercept.h"
     22 #include "nacl_io/kernel_proxy.h"
     23 #include "nacl_io/memfs/mem_fs.h"
     24 #include "nacl_io/osmman.h"
     25 #include "nacl_io/path.h"
     26 #include "nacl_io/typed_fs_factory.h"
     27 
     28 using namespace nacl_io;
     29 using namespace sdk_util;
     30 
     31 using ::testing::_;
     32 using ::testing::DoAll;
     33 using ::testing::Invoke;
     34 using ::testing::Return;
     35 using ::testing::SaveArg;
     36 using ::testing::SetArgPointee;
     37 using ::testing::StrEq;
     38 using ::testing::WithArgs;
     39 
     40 namespace {
     41 
     42 class KernelProxyTest_KernelProxy : public KernelProxy {
     43  public:
     44   Filesystem* RootFs() {
     45     ScopedFilesystem fs;
     46     Path path;
     47 
     48     AcquireFsAndRelPath("/", &fs, &path);
     49     return fs.get();
     50   }
     51 };
     52 
     53 class KernelProxyTest : public ::testing::Test {
     54  public:
     55   KernelProxyTest() {}
     56 
     57   void SetUp() {
     58     ASSERT_EQ(0, ki_push_state_for_testing());
     59     ASSERT_EQ(0, ki_init(&kp_));
     60     // Unmount the passthrough FS and mount a memfs.
     61     EXPECT_EQ(0, kp_.umount("/"));
     62     EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
     63   }
     64 
     65   void TearDown() { ki_uninit(); }
     66 
     67  protected:
     68   KernelProxyTest_KernelProxy kp_;
     69 };
     70 
     71 }  // namespace
     72 
     73 static int ki_fcntl_wrapper(int fd, int request, ...) {
     74   va_list ap;
     75   va_start(ap, request);
     76   int rtn = ki_fcntl(fd, request, ap);
     77   va_end(ap);
     78   return rtn;
     79 }
     80 
     81 /**
     82  * Test for fcntl commands F_SETFD and F_GETFD.  This
     83  * is tested here rather than in the mount_node tests
     84  * since the fd flags are not stored in the kernel_handle
     85  * or the filesystem node but directly in the FD mapping.
     86  */
     87 TEST_F(KernelProxyTest, Fcntl_GETFD) {
     88   int fd = ki_open("/test", O_RDWR | O_CREAT, 0777);
     89   ASSERT_NE(-1, fd);
     90 
     91   // FD flags should start as zero.
     92   ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD));
     93 
     94   // Check that setting FD_CLOEXEC works
     95   int flags = FD_CLOEXEC;
     96   ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags))
     97       << "fcntl failed with: " << strerror(errno);
     98   ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD));
     99 
    100   // Check that setting invalid flag causes EINVAL
    101   flags = FD_CLOEXEC + 1;
    102   ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags));
    103   ASSERT_EQ(EINVAL, errno);
    104 }
    105 
    106 TEST_F(KernelProxyTest, FileLeak) {
    107   const size_t buffer_size = 1024;
    108   char filename[128];
    109   int garbage[buffer_size];
    110 
    111   MemFs* filesystem = (MemFs*)kp_.RootFs();
    112   ScopedNode root;
    113 
    114   ASSERT_EQ(0, filesystem->Open(Path("/"), O_RDONLY, &root));
    115   ASSERT_EQ(0, root->ChildCount());
    116 
    117   for (int file_num = 0; file_num < 4096; file_num++) {
    118     sprintf(filename, "/foo%i.tmp", file_num++);
    119     int fd = ki_open(filename, O_WRONLY | O_CREAT, 0777);
    120     ASSERT_GT(fd, -1);
    121     ASSERT_EQ(1, root->ChildCount());
    122     ASSERT_EQ(buffer_size, ki_write(fd, garbage, buffer_size));
    123     ki_close(fd);
    124     ASSERT_EQ(0, ki_remove(filename));
    125   }
    126   ASSERT_EQ(0, root->ChildCount());
    127 }
    128 
    129 static bool g_handler_called = false;
    130 static void sighandler(int) { g_handler_called = true; }
    131 
    132 TEST_F(KernelProxyTest, Sigaction) {
    133   struct sigaction action;
    134   struct sigaction oaction;
    135   memset(&action, 0, sizeof(action));
    136 
    137   // Invalid signum
    138   ASSERT_EQ(-1, ki_sigaction(-1, NULL, &oaction));
    139   ASSERT_EQ(-1, ki_sigaction(SIGSTOP, NULL, &oaction));
    140   ASSERT_EQ(EINVAL, errno);
    141 
    142   // Get existing handler
    143   memset(&oaction, 0, sizeof(oaction));
    144   ASSERT_EQ(0, ki_sigaction(SIGINT, NULL, &oaction));
    145   ASSERT_EQ(SIG_DFL, oaction.sa_handler);
    146 
    147   // Attempt to set handler for unsupported signum
    148   action.sa_handler = sighandler;
    149   ASSERT_EQ(-1, ki_sigaction(SIGINT, &action, NULL));
    150   ASSERT_EQ(EINVAL, errno);
    151 
    152   // Attempt to set handler for supported signum
    153   action.sa_handler = sighandler;
    154   ASSERT_EQ(0, ki_sigaction(SIGWINCH, &action, NULL));
    155 
    156   memset(&oaction, 0, sizeof(oaction));
    157   ASSERT_EQ(0, ki_sigaction(SIGWINCH, NULL, &oaction));
    158   ASSERT_EQ((sighandler_t*)sighandler, (sighandler_t*)oaction.sa_handler);
    159 }
    160 
    161 TEST_F(KernelProxyTest, KillSignals) {
    162   // SIGSEGV can't be sent via kill(2)
    163   ASSERT_EQ(-1, ki_kill(0, SIGSEGV)) << "kill(SEGV) failed to return an error";
    164   ASSERT_EQ(EINVAL, errno) << "kill(SEGV) failed to set errno to EINVAL";
    165 
    166   // Our implemenation should understand SIGWINCH
    167   ASSERT_EQ(0, ki_kill(0, SIGWINCH)) << "kill(SIGWINCH) failed: " << errno;
    168 
    169   // And USR1/USR2
    170   ASSERT_EQ(0, ki_kill(0, SIGUSR1)) << "kill(SIGUSR1) failed: " << errno;
    171   ASSERT_EQ(0, ki_kill(0, SIGUSR2)) << "kill(SIGUSR2) failed: " << errno;
    172 }
    173 
    174 TEST_F(KernelProxyTest, KillPIDValues) {
    175   // Any PID other than 0, -1 and getpid() should yield ESRCH
    176   // since there is only one valid process under NaCl
    177   int mypid = getpid();
    178   ASSERT_EQ(0, ki_kill(0, SIGWINCH));
    179   ASSERT_EQ(0, ki_kill(-1, SIGWINCH));
    180   ASSERT_EQ(0, ki_kill(mypid, SIGWINCH));
    181 
    182   // Don't use mypid + 1 since getpid() actually returns -1
    183   // when the IRT interface is missing (e.g. within chrome),
    184   // and 0 is always a valid PID when calling kill().
    185   int invalid_pid = mypid + 10;
    186   ASSERT_EQ(-1, ki_kill(invalid_pid, SIGWINCH));
    187   ASSERT_EQ(ESRCH, errno);
    188 }
    189 
    190 TEST_F(KernelProxyTest, SignalValues) {
    191   ASSERT_EQ(ki_signal(SIGSEGV, sighandler), SIG_ERR)
    192       << "registering SEGV handler didn't fail";
    193   ASSERT_EQ(errno, EINVAL) << "signal(SEGV) failed to set errno to EINVAL";
    194 
    195   ASSERT_EQ(ki_signal(-1, sighandler), SIG_ERR)
    196       << "registering handler for invalid signal didn't fail";
    197   ASSERT_EQ(errno, EINVAL) << "signal(-1) failed to set errno to EINVAL";
    198 }
    199 
    200 TEST_F(KernelProxyTest, SignalHandlerValues) {
    201   // Unsupported signal.
    202   ASSERT_NE(SIG_ERR, ki_signal(SIGSEGV, SIG_DFL));
    203   ASSERT_EQ(SIG_ERR, ki_signal(SIGSEGV, SIG_IGN));
    204   ASSERT_EQ(SIG_ERR, ki_signal(SIGSEGV, sighandler));
    205 
    206   // Supported signal.
    207   ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, SIG_DFL));
    208   ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, SIG_IGN));
    209   ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, sighandler));
    210 }
    211 
    212 TEST_F(KernelProxyTest, SignalSigwinch) {
    213   g_handler_called = false;
    214 
    215   // Register WINCH handler
    216   sighandler_t newsig = sighandler;
    217   sighandler_t oldsig = ki_signal(SIGWINCH, newsig);
    218   ASSERT_NE(oldsig, SIG_ERR);
    219 
    220   // Send signal.
    221   ki_kill(0, SIGWINCH);
    222 
    223   // Verify that handler was called
    224   EXPECT_TRUE(g_handler_called);
    225 
    226   // Restore existing handler
    227   oldsig = ki_signal(SIGWINCH, oldsig);
    228 
    229   // Verify the our newsig was returned as previous handler
    230   ASSERT_EQ(oldsig, newsig);
    231 }
    232 
    233 TEST_F(KernelProxyTest, Rename) {
    234   // Create a dummy file
    235   int file1 = ki_open("/test1.txt", O_RDWR | O_CREAT, 0777);
    236   ASSERT_GT(file1, -1);
    237   ASSERT_EQ(0, ki_close(file1));
    238 
    239   // Test the renaming works
    240   ASSERT_EQ(0, ki_rename("/test1.txt", "/test2.txt"));
    241 
    242   // Test that renaming across mount points fails
    243   ASSERT_EQ(0, ki_mount("", "/foo", "memfs", 0, ""));
    244   ASSERT_EQ(-1, ki_rename("/test2.txt", "/foo/test2.txt"));
    245   ASSERT_EQ(EXDEV, errno);
    246 }
    247 
    248 TEST_F(KernelProxyTest, WorkingDirectory) {
    249   char text[1024];
    250 
    251   text[0] = 0;
    252   ki_getcwd(text, sizeof(text));
    253   EXPECT_STREQ("/", text);
    254 
    255   char* alloc = ki_getwd(NULL);
    256   EXPECT_EQ((char*)NULL, alloc);
    257   EXPECT_EQ(EFAULT, errno);
    258 
    259   text[0] = 0;
    260   alloc = ki_getwd(text);
    261   EXPECT_STREQ("/", alloc);
    262 
    263   EXPECT_EQ(-1, ki_chdir("/foo"));
    264   EXPECT_EQ(ENOENT, errno);
    265 
    266   EXPECT_EQ(0, ki_chdir("/"));
    267 
    268   EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
    269   EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
    270   EXPECT_EQ(EEXIST, errno);
    271 
    272   memset(text, 0, sizeof(text));
    273   EXPECT_EQ(0, ki_chdir("foo"));
    274   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    275   EXPECT_STREQ("/foo", text);
    276 
    277   memset(text, 0, sizeof(text));
    278   EXPECT_EQ(-1, ki_chdir("foo"));
    279   EXPECT_EQ(ENOENT, errno);
    280   EXPECT_EQ(0, ki_chdir(".."));
    281   EXPECT_EQ(0, ki_chdir("/foo"));
    282   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    283   EXPECT_STREQ("/foo", text);
    284 }
    285 
    286 TEST_F(KernelProxyTest, FDPathMapping) {
    287   char text[1024];
    288 
    289   int fd1, fd2, fd3, fd4, fd5;
    290 
    291   EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
    292   EXPECT_EQ(0, ki_mkdir("/foo/bar", S_IREAD | S_IWRITE));
    293   EXPECT_EQ(0, ki_mkdir("/example", S_IREAD | S_IWRITE));
    294   ki_chdir("/foo");
    295 
    296   fd1 = ki_open("/example", O_RDONLY, 0);
    297   EXPECT_NE(-1, fd1);
    298   EXPECT_EQ(ki_fchdir(fd1), 0);
    299   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    300   EXPECT_STREQ("/example", text);
    301 
    302   EXPECT_EQ(0, ki_chdir("/foo"));
    303   fd2 = ki_open("../example", O_RDONLY, 0);
    304   EXPECT_NE(-1, fd2);
    305   EXPECT_EQ(0, ki_fchdir(fd2));
    306   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    307   EXPECT_STREQ("/example", text);
    308 
    309   EXPECT_EQ(0, ki_chdir("/foo"));
    310   fd3 = ki_open("../test", O_CREAT | O_RDWR, 0777);
    311   EXPECT_NE(-1, fd3);
    312   EXPECT_EQ(-1, ki_fchdir(fd3));
    313   EXPECT_EQ(ENOTDIR, errno);
    314 
    315   EXPECT_EQ(0, ki_chdir("/foo"));
    316   fd4 = ki_open("bar", O_RDONLY, 0);
    317   EXPECT_EQ(0, ki_fchdir(fd4));
    318   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    319   EXPECT_STREQ("/foo/bar", text);
    320   EXPECT_EQ(0, ki_chdir("/example"));
    321   EXPECT_EQ(0, ki_fchdir(fd4));
    322   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    323   EXPECT_STREQ("/foo/bar", text);
    324 
    325   EXPECT_EQ(0, ki_chdir("/example"));
    326   fd5 = ki_dup(fd4);
    327   ASSERT_GT(fd5, -1);
    328   ASSERT_NE(fd4, fd5);
    329   EXPECT_EQ(0, ki_fchdir(fd5));
    330   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    331   EXPECT_STREQ("/foo/bar", text);
    332 
    333   fd5 = 123;
    334 
    335   EXPECT_EQ(0, ki_chdir("/example"));
    336   EXPECT_EQ(fd5, ki_dup2(fd4, fd5));
    337   EXPECT_EQ(0, ki_fchdir(fd5));
    338   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
    339   EXPECT_STREQ("/foo/bar", text);
    340 }
    341 
    342 TEST_F(KernelProxyTest, MemMountIO) {
    343   char text[1024];
    344   int fd1, fd2, fd3;
    345   int len;
    346 
    347   // Fail to delete non existant "/foo"
    348   EXPECT_EQ(-1, ki_rmdir("/foo"));
    349   EXPECT_EQ(ENOENT, errno);
    350 
    351   // Create "/foo"
    352   EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
    353   EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
    354   EXPECT_EQ(EEXIST, errno);
    355 
    356   // Delete "/foo"
    357   EXPECT_EQ(0, ki_rmdir("/foo"));
    358 
    359   // Recreate "/foo"
    360   EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
    361 
    362   // Fail to open "/foo/bar"
    363   EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY, 0));
    364   EXPECT_EQ(ENOENT, errno);
    365 
    366   // Create bar "/foo/bar"
    367   fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT, 0777);
    368   ASSERT_NE(-1, fd1);
    369 
    370   // Open (optionally create) bar "/foo/bar"
    371   fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT, 0777);
    372   ASSERT_NE(-1, fd2);
    373 
    374   // Fail to exclusively create bar "/foo/bar"
    375   EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL, 0777));
    376   EXPECT_EQ(EEXIST, errno);
    377 
    378   // Write hello and world to same node with different descriptors
    379   // so that we overwrite each other
    380   EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
    381   EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
    382 
    383   fd3 = ki_open("/foo/bar", O_RDONLY, 0);
    384   ASSERT_NE(-1, fd3);
    385 
    386   len = ki_read(fd3, text, sizeof(text));
    387   ASSERT_EQ(5, len);
    388   text[len] = 0;
    389   EXPECT_STREQ("HELLO", text);
    390   EXPECT_EQ(0, ki_close(fd1));
    391   EXPECT_EQ(0, ki_close(fd2));
    392 
    393   fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND, 0);
    394   ASSERT_NE(-1, fd1);
    395   EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
    396 
    397   len = ki_read(fd3, text, sizeof(text));
    398   ASSERT_EQ(5, len);
    399   text[len] = 0;
    400   EXPECT_STREQ("WORLD", text);
    401 
    402   fd2 = ki_open("/foo/bar", O_RDONLY, 0);
    403   ASSERT_NE(-1, fd2);
    404   len = ki_read(fd2, text, sizeof(text));
    405   if (len > 0)
    406     text[len] = 0;
    407   EXPECT_EQ(10, len);
    408   EXPECT_STREQ("HELLOWORLD", text);
    409 }
    410 
    411 TEST_F(KernelProxyTest, MemMountFTruncate) {
    412   char text[1024];
    413   int fd1, fd2;
    414 
    415   // Open a file write only, write some text, then test that using a
    416   // separate file descriptor pointing to it that it is correctly
    417   // truncated at a specified number of bytes (2).
    418   fd1 = ki_open("/trunc", O_WRONLY | O_CREAT, 0777);
    419   ASSERT_NE(-1, fd1);
    420   fd2 = ki_open("/trunc", O_RDONLY, 0);
    421   ASSERT_NE(-1, fd2);
    422   EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
    423   EXPECT_EQ(0, ki_ftruncate(fd1, 2));
    424   // Verify the remaining file (using fd2, opened pre-truncation) is
    425   // only 2 bytes in length.
    426   EXPECT_EQ(2, ki_read(fd2, text, sizeof(text)));
    427   EXPECT_EQ(0, ki_close(fd1));
    428   EXPECT_EQ(0, ki_close(fd2));
    429 }
    430 
    431 TEST_F(KernelProxyTest, MemMountTruncate) {
    432   char text[1024];
    433   int fd1;
    434 
    435   // Open a file write only, write some text, then test that by
    436   // referring to it by its path and truncating it we correctly truncate
    437   // it at a specified number of bytes (2).
    438   fd1 = ki_open("/trunc", O_WRONLY | O_CREAT, 0777);
    439   ASSERT_NE(-1, fd1);
    440   EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
    441   EXPECT_EQ(0, ki_close(fd1));
    442   EXPECT_EQ(0, ki_truncate("/trunc", 2));
    443   // Verify the text is only 2 bytes long with new file descriptor.
    444   fd1 = ki_open("/trunc", O_RDONLY, 0);
    445   ASSERT_NE(-1, fd1);
    446   EXPECT_EQ(2, ki_read(fd1, text, sizeof(text)));
    447   EXPECT_EQ(0, ki_close(fd1));
    448 }
    449 
    450 TEST_F(KernelProxyTest, MemMountLseek) {
    451   int fd = ki_open("/foo", O_CREAT | O_RDWR, 0777);
    452   ASSERT_GT(fd, -1);
    453   ASSERT_EQ(9, ki_write(fd, "Some text", 9));
    454 
    455   ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
    456   ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_END));
    457   ASSERT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
    458   ASSERT_EQ(EINVAL, errno);
    459 
    460   // Seek past end of file.
    461   ASSERT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
    462   char buffer[4];
    463   memset(&buffer[0], 0xfe, 4);
    464   ASSERT_EQ(9, ki_lseek(fd, -4, SEEK_END));
    465   ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
    466   ASSERT_EQ(4, ki_read(fd, &buffer[0], 4));
    467   ASSERT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
    468 }
    469 
    470 TEST_F(KernelProxyTest, CloseTwice) {
    471   int fd = ki_open("/foo", O_CREAT | O_RDWR, 0777);
    472   ASSERT_GT(fd, -1);
    473 
    474   EXPECT_EQ(9, ki_write(fd, "Some text", 9));
    475 
    476   int fd2 = ki_dup(fd);
    477   ASSERT_GT(fd2, -1);
    478 
    479   EXPECT_EQ(0, ki_close(fd));
    480   EXPECT_EQ(0, ki_close(fd2));
    481 }
    482 
    483 TEST_F(KernelProxyTest, MemMountDup) {
    484   int fd = ki_open("/foo", O_CREAT | O_RDWR, 0777);
    485   ASSERT_GT(fd, -1);
    486 
    487   int dup_fd = ki_dup(fd);
    488   ASSERT_NE(-1, dup_fd);
    489 
    490   ASSERT_EQ(9, ki_write(fd, "Some text", 9));
    491   ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
    492   ASSERT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
    493 
    494   int dup2_fd = 123;
    495   ASSERT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
    496   ASSERT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
    497 
    498   int new_fd = ki_open("/bar", O_CREAT | O_RDWR, 0777);
    499 
    500   ASSERT_EQ(fd, ki_dup2(new_fd, fd));
    501   // fd, new_fd -> "/bar"
    502   // dup_fd, dup2_fd -> "/foo"
    503 
    504   // We should still be able to write to dup_fd (i.e. it should not be closed).
    505   ASSERT_EQ(4, ki_write(dup_fd, "more", 4));
    506 
    507   ASSERT_EQ(0, ki_close(dup2_fd));
    508   // fd, new_fd -> "/bar"
    509   // dup_fd -> "/foo"
    510 
    511   ASSERT_EQ(dup_fd, ki_dup2(fd, dup_fd));
    512   // fd, new_fd, dup_fd -> "/bar"
    513 }
    514 
    515 TEST_F(KernelProxyTest, Lstat) {
    516   int fd = ki_open("/foo", O_CREAT | O_RDWR, 0777);
    517   ASSERT_GT(fd, -1);
    518   ASSERT_EQ(0, ki_mkdir("/bar", S_IREAD | S_IWRITE));
    519 
    520   struct stat buf;
    521   EXPECT_EQ(0, ki_lstat("/foo", &buf));
    522   EXPECT_EQ(0, buf.st_size);
    523   EXPECT_TRUE(S_ISREG(buf.st_mode));
    524 
    525   EXPECT_EQ(0, ki_lstat("/bar", &buf));
    526   EXPECT_EQ(0, buf.st_size);
    527   EXPECT_TRUE(S_ISDIR(buf.st_mode));
    528 
    529   EXPECT_EQ(-1, ki_lstat("/no-such-file", &buf));
    530   EXPECT_EQ(ENOENT, errno);
    531 }
    532 
    533 TEST_F(KernelProxyTest, OpenWithMode) {
    534   int fd = ki_open("/foo", O_CREAT | O_RDWR, 0723);
    535   ASSERT_GT(fd, -1);
    536 
    537   struct stat buf;
    538   EXPECT_EQ(0, ki_lstat("/foo", &buf));
    539   EXPECT_EQ(0723, buf.st_mode & ~S_IFMT);
    540 }
    541 
    542 TEST_F(KernelProxyTest, UseAfterClose) {
    543   int fd = ki_open("/dummy", O_CREAT | O_WRONLY, 0777);
    544   ASSERT_GT(fd, -1);
    545   EXPECT_EQ(5, ki_write(fd, "hello", 5));
    546   EXPECT_EQ(0, ki_close(fd));
    547   EXPECT_EQ(-1, ki_write(fd, "hello", 5));
    548   EXPECT_EQ(EBADF, errno);
    549 }
    550 
    551 namespace {
    552 
    553 StringMap_t g_string_map;
    554 bool g_fs_ioctl_called;
    555 int g_fs_dev;
    556 
    557 class KernelProxyMountTest_Filesystem : public MemFs {
    558  public:
    559   virtual Error Init(const FsInitArgs& args) {
    560     MemFs::Init(args);
    561 
    562     g_string_map = args.string_map;
    563     g_fs_dev = args.dev;
    564 
    565     if (g_string_map.find("false") != g_string_map.end())
    566       return EINVAL;
    567     return 0;
    568   }
    569 
    570   virtual Error Filesystem_VIoctl(int request, va_list arglist) {
    571     g_fs_ioctl_called = true;
    572     return 0;
    573   }
    574 
    575   friend class TypedFsFactory<KernelProxyMountTest_Filesystem>;
    576 };
    577 
    578 class KernelProxyMountTest_KernelProxy : public KernelProxy {
    579   virtual Error Init(PepperInterface* ppapi) {
    580     KernelProxy::Init(NULL);
    581     factories_["initfs"] = new TypedFsFactory<KernelProxyMountTest_Filesystem>;
    582     return 0;
    583   }
    584 };
    585 
    586 class KernelProxyMountTest : public ::testing::Test {
    587  public:
    588   KernelProxyMountTest() {}
    589 
    590   void SetUp() {
    591     g_string_map.clear();
    592     g_fs_dev = -1;
    593     g_fs_ioctl_called = false;
    594 
    595     ASSERT_EQ(0, ki_push_state_for_testing());
    596     ASSERT_EQ(0, ki_init(&kp_));
    597   }
    598 
    599   void TearDown() {
    600     g_string_map.clear();
    601     ki_uninit();
    602   }
    603 
    604  protected:
    605   KernelProxyMountTest_KernelProxy kp_;
    606 };
    607 
    608 // Helper function for calling ki_ioctl without having
    609 // to construct a va_list.
    610 int ki_ioctl_wrapper(int fd, int request, ...) {
    611   va_list ap;
    612   va_start(ap, request);
    613   int rtn = ki_ioctl(fd, request, ap);
    614   va_end(ap);
    615   return rtn;
    616 }
    617 
    618 }  // namespace
    619 
    620 TEST_F(KernelProxyMountTest, MountInit) {
    621   int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
    622 
    623   EXPECT_EQ("bar", g_string_map["foo"]);
    624   EXPECT_EQ(-1, res1);
    625   EXPECT_EQ(EINVAL, errno);
    626 
    627   int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
    628   EXPECT_NE(-1, res2);
    629   EXPECT_EQ("y", g_string_map["x"]);
    630 }
    631 
    632 TEST_F(KernelProxyMountTest, MountAndIoctl) {
    633   ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, ""));
    634   ASSERT_NE(-1, g_fs_dev);
    635 
    636   char path[100];
    637   snprintf(path, 100, "dev/fs/%d", g_fs_dev);
    638 
    639   int fd = ki_open(path, O_RDONLY, 0);
    640   ASSERT_GT(fd, -1);
    641 
    642   EXPECT_EQ(0, ki_ioctl_wrapper(fd, 0xdeadbeef));
    643   EXPECT_EQ(true, g_fs_ioctl_called);
    644 }
    645 
    646 static void mount_callback(const char* source,
    647                            const char* target,
    648                            const char* filesystemtype,
    649                            unsigned long mountflags,
    650                            const void* data,
    651                            dev_t dev,
    652                            void* user_data) {
    653   EXPECT_STREQ("/", source);
    654   EXPECT_STREQ("/mnt1", target);
    655   EXPECT_STREQ("initfs", filesystemtype);
    656   EXPECT_EQ(0, mountflags);
    657   EXPECT_STREQ("", (const char*) data);
    658   EXPECT_EQ(g_fs_dev, dev);
    659 
    660   bool* callback_called = static_cast<bool*>(user_data);
    661   *callback_called = true;
    662 }
    663 
    664 TEST_F(KernelProxyMountTest, MountCallback) {
    665   bool callback_called = false;
    666   kp_.SetMountCallback(&mount_callback, &callback_called);
    667   ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, ""));
    668   ASSERT_NE(-1, g_fs_dev);
    669   EXPECT_EQ(true, callback_called);
    670 }
    671 
    672 namespace {
    673 
    674 int g_MMapCount = 0;
    675 
    676 class KernelProxyMMapTest_Node : public Node {
    677  public:
    678   KernelProxyMMapTest_Node(Filesystem* filesystem)
    679       : Node(filesystem), node_mmap_count_(0) {
    680     EXPECT_EQ(0, Init(0));
    681   }
    682 
    683   virtual Error MMap(void* addr,
    684                      size_t length,
    685                      int prot,
    686                      int flags,
    687                      size_t offset,
    688                      void** out_addr) {
    689     node_mmap_count_++;
    690     switch (g_MMapCount++) {
    691       case 0:
    692         *out_addr = reinterpret_cast<void*>(0x1000);
    693         break;
    694       case 1:
    695         *out_addr = reinterpret_cast<void*>(0x2000);
    696         break;
    697       case 2:
    698         *out_addr = reinterpret_cast<void*>(0x3000);
    699         break;
    700       default:
    701         return EPERM;
    702     }
    703 
    704     return 0;
    705   }
    706 
    707  private:
    708   int node_mmap_count_;
    709 };
    710 
    711 class KernelProxyMMapTest_Filesystem : public Filesystem {
    712  public:
    713   virtual Error OpenWithMode(const Path& path, int open_flags,
    714                              mode_t mode, ScopedNode* out_node) {
    715     out_node->reset(new KernelProxyMMapTest_Node(this));
    716     return 0;
    717   }
    718 
    719   virtual Error OpenResource(const Path& path, ScopedNode* out_node) {
    720     out_node->reset(NULL);
    721     return ENOSYS;
    722   }
    723   virtual Error Unlink(const Path& path) { return ENOSYS; }
    724   virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
    725   virtual Error Rmdir(const Path& path) { return ENOSYS; }
    726   virtual Error Remove(const Path& path) { return ENOSYS; }
    727   virtual Error Rename(const Path& path, const Path& newpath) { return ENOSYS; }
    728 
    729   friend class TypedFsFactory<KernelProxyMMapTest_Filesystem>;
    730 };
    731 
    732 class KernelProxyMMapTest_KernelProxy : public KernelProxy {
    733   virtual Error Init(PepperInterface* ppapi) {
    734     KernelProxy::Init(NULL);
    735     factories_["mmapfs"] = new TypedFsFactory<KernelProxyMMapTest_Filesystem>;
    736     return 0;
    737   }
    738 };
    739 
    740 class KernelProxyMMapTest : public ::testing::Test {
    741  public:
    742   KernelProxyMMapTest() {}
    743 
    744   void SetUp() {
    745     ASSERT_EQ(0, ki_push_state_for_testing());
    746     ASSERT_EQ(0, ki_init(&kp_));
    747   }
    748 
    749   void TearDown() { ki_uninit(); }
    750 
    751  private:
    752   KernelProxyMMapTest_KernelProxy kp_;
    753 };
    754 
    755 }  // namespace
    756 
    757 TEST_F(KernelProxyMMapTest, MMap) {
    758   ASSERT_EQ(0, ki_umount("/"));
    759   ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
    760   int fd = ki_open("/file", O_RDWR | O_CREAT, 0777);
    761   ASSERT_NE(-1, fd);
    762 
    763   void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    764   ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1);
    765   ASSERT_EQ(1, g_MMapCount);
    766 
    767   void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    768   ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2);
    769   ASSERT_EQ(2, g_MMapCount);
    770 
    771   void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    772   ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3);
    773   ASSERT_EQ(3, g_MMapCount);
    774 
    775   ki_close(fd);
    776 
    777   // We no longer track mmap'd regions, so munmap is a no-op.
    778   ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
    779   // We don't track regions, so the mmap count hasn't changed.
    780   ASSERT_EQ(3, g_MMapCount);
    781 }
    782 
    783 namespace {
    784 
    785 class SingletonFsFactory : public FsFactory {
    786  public:
    787   SingletonFsFactory(const ScopedFilesystem& filesystem) : mount_(filesystem) {}
    788 
    789   virtual Error CreateFilesystem(const FsInitArgs& args,
    790                                  ScopedFilesystem* out_fs) {
    791     *out_fs = mount_;
    792     return 0;
    793   }
    794 
    795  private:
    796   ScopedFilesystem mount_;
    797 };
    798 
    799 class KernelProxyErrorTest_KernelProxy : public KernelProxy {
    800  public:
    801   KernelProxyErrorTest_KernelProxy() : fs_(new MockFs) {}
    802 
    803   virtual Error Init(PepperInterface* ppapi) {
    804     KernelProxy::Init(ppapi);
    805     factories_["testfs"] = new SingletonFsFactory(fs_);
    806 
    807     EXPECT_CALL(*fs_, Destroy()).Times(1);
    808     return 0;
    809   }
    810 
    811   ScopedRef<MockFs> fs() { return fs_; }
    812 
    813  private:
    814   ScopedRef<MockFs> fs_;
    815 };
    816 
    817 class KernelProxyErrorTest : public ::testing::Test {
    818  public:
    819   KernelProxyErrorTest() {}
    820 
    821   void SetUp() {
    822     ASSERT_EQ(0, ki_push_state_for_testing());
    823     ASSERT_EQ(0, ki_init(&kp_));
    824     // Unmount the passthrough FS and mount a testfs.
    825     EXPECT_EQ(0, kp_.umount("/"));
    826     EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
    827   }
    828 
    829   void TearDown() { ki_uninit(); }
    830 
    831   ScopedRef<MockFs> fs() { return kp_.fs(); }
    832 
    833  private:
    834   KernelProxyErrorTest_KernelProxy kp_;
    835 };
    836 
    837 }  // namespace
    838 
    839 TEST_F(KernelProxyErrorTest, WriteError) {
    840   ScopedRef<MockFs> mock_fs(fs());
    841   ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
    842   EXPECT_CALL(*mock_fs, OpenWithMode(_, _, _, _))
    843       .WillOnce(DoAll(SetArgPointee<3>(mock_node), Return(0)));
    844 
    845   EXPECT_CALL(*mock_node, Write(_, _, _, _))
    846       .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
    847                       Return(1234)));       // Returned error 1234.
    848 
    849   EXPECT_CALL(*mock_node, Destroy()).Times(1);
    850 
    851   int fd = ki_open("/dummy", O_WRONLY, 0);
    852   EXPECT_NE(0, fd);
    853 
    854   char buf[20];
    855   EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
    856   // The Filesystem should be able to return whatever error it wants and have it
    857   // propagate through.
    858   EXPECT_EQ(1234, errno);
    859 }
    860 
    861 TEST_F(KernelProxyErrorTest, ReadError) {
    862   ScopedRef<MockFs> mock_fs(fs());
    863   ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
    864   EXPECT_CALL(*mock_fs, OpenWithMode(_, _, _, _))
    865       .WillOnce(DoAll(SetArgPointee<3>(mock_node), Return(0)));
    866 
    867   EXPECT_CALL(*mock_node, Read(_, _, _, _))
    868       .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
    869                       Return(1234)));       // Returned error 1234.
    870 
    871   EXPECT_CALL(*mock_node, Destroy()).Times(1);
    872 
    873   int fd = ki_open("/dummy", O_RDONLY, 0);
    874   EXPECT_NE(0, fd);
    875 
    876   char buf[20];
    877   EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
    878   // The Filesystem should be able to return whatever error it wants and have it
    879   // propagate through.
    880   EXPECT_EQ(1234, errno);
    881 }
    882