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);
     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);
    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);
    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);
    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);
    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);
    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);
    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));
    364   EXPECT_EQ(ENOENT, errno);
    365 
    366   // Create bar "/foo/bar"
    367   fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT);
    368   ASSERT_NE(-1, fd1);
    369 
    370   // Open (optionally create) bar "/foo/bar"
    371   fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT);
    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));
    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);
    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);
    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);
    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);
    419   ASSERT_NE(-1, fd1);
    420   fd2 = ki_open("/trunc", O_RDONLY);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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, UseAfterClose) {
    534   int fd = ki_open("/dummy", O_CREAT | O_WRONLY);
    535   ASSERT_GT(fd, -1);
    536   EXPECT_EQ(5, ki_write(fd, "hello", 5));
    537   EXPECT_EQ(0, ki_close(fd));
    538   EXPECT_EQ(-1, ki_write(fd, "hello", 5));
    539   EXPECT_EQ(EBADF, errno);
    540 }
    541 
    542 namespace {
    543 
    544 StringMap_t g_string_map;
    545 bool g_fs_ioctl_called;
    546 int g_fs_dev;
    547 
    548 class KernelProxyMountTest_Filesystem : public MemFs {
    549  public:
    550   virtual Error Init(const FsInitArgs& args) {
    551     MemFs::Init(args);
    552 
    553     g_string_map = args.string_map;
    554     g_fs_dev = args.dev;
    555 
    556     if (g_string_map.find("false") != g_string_map.end())
    557       return EINVAL;
    558     return 0;
    559   }
    560 
    561   virtual Error Filesystem_VIoctl(int request, va_list arglist) {
    562     g_fs_ioctl_called = true;
    563     return 0;
    564   }
    565 
    566   friend class TypedFsFactory<KernelProxyMountTest_Filesystem>;
    567 };
    568 
    569 class KernelProxyMountTest_KernelProxy : public KernelProxy {
    570   virtual Error Init(PepperInterface* ppapi) {
    571     KernelProxy::Init(NULL);
    572     factories_["initfs"] = new TypedFsFactory<KernelProxyMountTest_Filesystem>;
    573     return 0;
    574   }
    575 };
    576 
    577 class KernelProxyMountTest : public ::testing::Test {
    578  public:
    579   KernelProxyMountTest() {}
    580 
    581   void SetUp() {
    582     g_string_map.clear();
    583     g_fs_dev = -1;
    584     g_fs_ioctl_called = false;
    585 
    586     ASSERT_EQ(0, ki_push_state_for_testing());
    587     ASSERT_EQ(0, ki_init(&kp_));
    588   }
    589 
    590   void TearDown() {
    591     g_string_map.clear();
    592     ki_uninit();
    593   }
    594 
    595  private:
    596   KernelProxyMountTest_KernelProxy kp_;
    597 };
    598 
    599 // Helper function for calling ki_ioctl without having
    600 // to construct a va_list.
    601 int ki_ioctl_wrapper(int fd, int request, ...) {
    602   va_list ap;
    603   va_start(ap, request);
    604   int rtn = ki_ioctl(fd, request, ap);
    605   va_end(ap);
    606   return rtn;
    607 }
    608 
    609 }  // namespace
    610 
    611 TEST_F(KernelProxyMountTest, MountInit) {
    612   int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
    613 
    614   EXPECT_EQ("bar", g_string_map["foo"]);
    615   EXPECT_EQ(-1, res1);
    616   EXPECT_EQ(EINVAL, errno);
    617 
    618   int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
    619   EXPECT_NE(-1, res2);
    620   EXPECT_EQ("y", g_string_map["x"]);
    621 }
    622 
    623 TEST_F(KernelProxyMountTest, MountAndIoctl) {
    624   ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, ""));
    625   ASSERT_NE(-1, g_fs_dev);
    626 
    627   char path[100];
    628   snprintf(path, 100, "dev/fs/%d", g_fs_dev);
    629 
    630   int fd = ki_open(path, O_RDONLY);
    631   ASSERT_GT(fd, -1);
    632 
    633   EXPECT_EQ(0, ki_ioctl_wrapper(fd, 0xdeadbeef));
    634   EXPECT_EQ(true, g_fs_ioctl_called);
    635 }
    636 
    637 namespace {
    638 
    639 int g_MMapCount = 0;
    640 
    641 class KernelProxyMMapTest_Node : public Node {
    642  public:
    643   KernelProxyMMapTest_Node(Filesystem* filesystem)
    644       : Node(filesystem), node_mmap_count_(0) {
    645     EXPECT_EQ(0, Init(0));
    646   }
    647 
    648   virtual Error MMap(void* addr,
    649                      size_t length,
    650                      int prot,
    651                      int flags,
    652                      size_t offset,
    653                      void** out_addr) {
    654     node_mmap_count_++;
    655     switch (g_MMapCount++) {
    656       case 0:
    657         *out_addr = reinterpret_cast<void*>(0x1000);
    658         break;
    659       case 1:
    660         *out_addr = reinterpret_cast<void*>(0x2000);
    661         break;
    662       case 2:
    663         *out_addr = reinterpret_cast<void*>(0x3000);
    664         break;
    665       default:
    666         return EPERM;
    667     }
    668 
    669     return 0;
    670   }
    671 
    672  private:
    673   int node_mmap_count_;
    674 };
    675 
    676 class KernelProxyMMapTest_Filesystem : public Filesystem {
    677  public:
    678   virtual Error Access(const Path& path, int a_mode) { return 0; }
    679   virtual Error Open(const Path& path, int mode, ScopedNode* out_node) {
    680     out_node->reset(new KernelProxyMMapTest_Node(this));
    681     return 0;
    682   }
    683 
    684   virtual Error OpenResource(const Path& path, ScopedNode* out_node) {
    685     out_node->reset(NULL);
    686     return ENOSYS;
    687   }
    688   virtual Error Unlink(const Path& path) { return ENOSYS; }
    689   virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
    690   virtual Error Rmdir(const Path& path) { return ENOSYS; }
    691   virtual Error Remove(const Path& path) { return ENOSYS; }
    692   virtual Error Rename(const Path& path, const Path& newpath) { return ENOSYS; }
    693 
    694   friend class TypedFsFactory<KernelProxyMMapTest_Filesystem>;
    695 };
    696 
    697 class KernelProxyMMapTest_KernelProxy : public KernelProxy {
    698   virtual Error Init(PepperInterface* ppapi) {
    699     KernelProxy::Init(NULL);
    700     factories_["mmapfs"] = new TypedFsFactory<KernelProxyMMapTest_Filesystem>;
    701     return 0;
    702   }
    703 };
    704 
    705 class KernelProxyMMapTest : public ::testing::Test {
    706  public:
    707   KernelProxyMMapTest() {}
    708 
    709   void SetUp() {
    710     ASSERT_EQ(0, ki_push_state_for_testing());
    711     ASSERT_EQ(0, ki_init(&kp_));
    712   }
    713 
    714   void TearDown() { ki_uninit(); }
    715 
    716  private:
    717   KernelProxyMMapTest_KernelProxy kp_;
    718 };
    719 
    720 }  // namespace
    721 
    722 TEST_F(KernelProxyMMapTest, MMap) {
    723   ASSERT_EQ(0, ki_umount("/"));
    724   ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
    725   int fd = ki_open("/file", O_RDWR | O_CREAT);
    726   ASSERT_NE(-1, fd);
    727 
    728   void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    729   ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1);
    730   ASSERT_EQ(1, g_MMapCount);
    731 
    732   void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    733   ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2);
    734   ASSERT_EQ(2, g_MMapCount);
    735 
    736   void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
    737   ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3);
    738   ASSERT_EQ(3, g_MMapCount);
    739 
    740   ki_close(fd);
    741 
    742   // We no longer track mmap'd regions, so munmap is a no-op.
    743   ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
    744   // We don't track regions, so the mmap count hasn't changed.
    745   ASSERT_EQ(3, g_MMapCount);
    746 }
    747 
    748 namespace {
    749 
    750 class SingletonFsFactory : public FsFactory {
    751  public:
    752   SingletonFsFactory(const ScopedFilesystem& filesystem) : mount_(filesystem) {}
    753 
    754   virtual Error CreateFilesystem(const FsInitArgs& args,
    755                                  ScopedFilesystem* out_fs) {
    756     *out_fs = mount_;
    757     return 0;
    758   }
    759 
    760  private:
    761   ScopedFilesystem mount_;
    762 };
    763 
    764 class KernelProxyErrorTest_KernelProxy : public KernelProxy {
    765  public:
    766   KernelProxyErrorTest_KernelProxy() : fs_(new MockFs) {}
    767 
    768   virtual Error Init(PepperInterface* ppapi) {
    769     KernelProxy::Init(ppapi);
    770     factories_["testfs"] = new SingletonFsFactory(fs_);
    771 
    772     EXPECT_CALL(*fs_, Destroy()).Times(1);
    773     return 0;
    774   }
    775 
    776   ScopedRef<MockFs> fs() { return fs_; }
    777 
    778  private:
    779   ScopedRef<MockFs> fs_;
    780 };
    781 
    782 class KernelProxyErrorTest : public ::testing::Test {
    783  public:
    784   KernelProxyErrorTest() {}
    785 
    786   void SetUp() {
    787     ASSERT_EQ(0, ki_push_state_for_testing());
    788     ASSERT_EQ(0, ki_init(&kp_));
    789     // Unmount the passthrough FS and mount a testfs.
    790     EXPECT_EQ(0, kp_.umount("/"));
    791     EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
    792   }
    793 
    794   void TearDown() { ki_uninit(); }
    795 
    796   ScopedRef<MockFs> fs() { return kp_.fs(); }
    797 
    798  private:
    799   KernelProxyErrorTest_KernelProxy kp_;
    800 };
    801 
    802 }  // namespace
    803 
    804 TEST_F(KernelProxyErrorTest, WriteError) {
    805   ScopedRef<MockFs> mock_fs(fs());
    806   ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
    807   EXPECT_CALL(*mock_fs, Open(_, _, _))
    808       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
    809 
    810   EXPECT_CALL(*mock_node, Write(_, _, _, _))
    811       .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
    812                       Return(1234)));       // Returned error 1234.
    813 
    814   EXPECT_CALL(*mock_node, Destroy()).Times(1);
    815 
    816   int fd = ki_open("/dummy", O_WRONLY);
    817   EXPECT_NE(0, fd);
    818 
    819   char buf[20];
    820   EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
    821   // The Filesystem should be able to return whatever error it wants and have it
    822   // propagate through.
    823   EXPECT_EQ(1234, errno);
    824 }
    825 
    826 TEST_F(KernelProxyErrorTest, ReadError) {
    827   ScopedRef<MockFs> mock_fs(fs());
    828   ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
    829   EXPECT_CALL(*mock_fs, Open(_, _, _))
    830       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
    831 
    832   EXPECT_CALL(*mock_node, Read(_, _, _, _))
    833       .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
    834                       Return(1234)));       // Returned error 1234.
    835 
    836   EXPECT_CALL(*mock_node, Destroy()).Times(1);
    837 
    838   int fd = ki_open("/dummy", O_RDONLY);
    839   EXPECT_NE(0, fd);
    840 
    841   char buf[20];
    842   EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
    843   // The Filesystem should be able to return whatever error it wants and have it
    844   // propagate through.
    845   EXPECT_EQ(1234, errno);
    846 }
    847