Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / tests / nacl_io_test / kernel_proxy_test.cc
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  protected:
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 static void mount_callback(const char* source,
638                            const char* target,
639                            const char* filesystemtype,
640                            unsigned long mountflags,
641                            const void* data,
642                            dev_t dev,
643                            void* user_data) {
644   EXPECT_STREQ("/", source);
645   EXPECT_STREQ("/mnt1", target);
646   EXPECT_STREQ("initfs", filesystemtype);
647   EXPECT_EQ(0, mountflags);
648   EXPECT_STREQ("", (const char*) data);
649   EXPECT_EQ(g_fs_dev, dev);
650
651   bool* callback_called = static_cast<bool*>(user_data);
652   *callback_called = true;
653 }
654
655 TEST_F(KernelProxyMountTest, MountCallback) {
656   bool callback_called = false;
657   kp_.SetMountCallback(&mount_callback, &callback_called);
658   ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, ""));
659   ASSERT_NE(-1, g_fs_dev);
660   EXPECT_EQ(true, callback_called);
661 }
662
663 namespace {
664
665 int g_MMapCount = 0;
666
667 class KernelProxyMMapTest_Node : public Node {
668  public:
669   KernelProxyMMapTest_Node(Filesystem* filesystem)
670       : Node(filesystem), node_mmap_count_(0) {
671     EXPECT_EQ(0, Init(0));
672   }
673
674   virtual Error MMap(void* addr,
675                      size_t length,
676                      int prot,
677                      int flags,
678                      size_t offset,
679                      void** out_addr) {
680     node_mmap_count_++;
681     switch (g_MMapCount++) {
682       case 0:
683         *out_addr = reinterpret_cast<void*>(0x1000);
684         break;
685       case 1:
686         *out_addr = reinterpret_cast<void*>(0x2000);
687         break;
688       case 2:
689         *out_addr = reinterpret_cast<void*>(0x3000);
690         break;
691       default:
692         return EPERM;
693     }
694
695     return 0;
696   }
697
698  private:
699   int node_mmap_count_;
700 };
701
702 class KernelProxyMMapTest_Filesystem : public Filesystem {
703  public:
704   virtual Error Access(const Path& path, int a_mode) { return 0; }
705   virtual Error Open(const Path& path, int mode, ScopedNode* out_node) {
706     out_node->reset(new KernelProxyMMapTest_Node(this));
707     return 0;
708   }
709
710   virtual Error OpenResource(const Path& path, ScopedNode* out_node) {
711     out_node->reset(NULL);
712     return ENOSYS;
713   }
714   virtual Error Unlink(const Path& path) { return ENOSYS; }
715   virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
716   virtual Error Rmdir(const Path& path) { return ENOSYS; }
717   virtual Error Remove(const Path& path) { return ENOSYS; }
718   virtual Error Rename(const Path& path, const Path& newpath) { return ENOSYS; }
719
720   friend class TypedFsFactory<KernelProxyMMapTest_Filesystem>;
721 };
722
723 class KernelProxyMMapTest_KernelProxy : public KernelProxy {
724   virtual Error Init(PepperInterface* ppapi) {
725     KernelProxy::Init(NULL);
726     factories_["mmapfs"] = new TypedFsFactory<KernelProxyMMapTest_Filesystem>;
727     return 0;
728   }
729 };
730
731 class KernelProxyMMapTest : public ::testing::Test {
732  public:
733   KernelProxyMMapTest() {}
734
735   void SetUp() {
736     ASSERT_EQ(0, ki_push_state_for_testing());
737     ASSERT_EQ(0, ki_init(&kp_));
738   }
739
740   void TearDown() { ki_uninit(); }
741
742  private:
743   KernelProxyMMapTest_KernelProxy kp_;
744 };
745
746 }  // namespace
747
748 TEST_F(KernelProxyMMapTest, MMap) {
749   ASSERT_EQ(0, ki_umount("/"));
750   ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
751   int fd = ki_open("/file", O_RDWR | O_CREAT);
752   ASSERT_NE(-1, fd);
753
754   void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
755   ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1);
756   ASSERT_EQ(1, g_MMapCount);
757
758   void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
759   ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2);
760   ASSERT_EQ(2, g_MMapCount);
761
762   void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
763   ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3);
764   ASSERT_EQ(3, g_MMapCount);
765
766   ki_close(fd);
767
768   // We no longer track mmap'd regions, so munmap is a no-op.
769   ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
770   // We don't track regions, so the mmap count hasn't changed.
771   ASSERT_EQ(3, g_MMapCount);
772 }
773
774 namespace {
775
776 class SingletonFsFactory : public FsFactory {
777  public:
778   SingletonFsFactory(const ScopedFilesystem& filesystem) : mount_(filesystem) {}
779
780   virtual Error CreateFilesystem(const FsInitArgs& args,
781                                  ScopedFilesystem* out_fs) {
782     *out_fs = mount_;
783     return 0;
784   }
785
786  private:
787   ScopedFilesystem mount_;
788 };
789
790 class KernelProxyErrorTest_KernelProxy : public KernelProxy {
791  public:
792   KernelProxyErrorTest_KernelProxy() : fs_(new MockFs) {}
793
794   virtual Error Init(PepperInterface* ppapi) {
795     KernelProxy::Init(ppapi);
796     factories_["testfs"] = new SingletonFsFactory(fs_);
797
798     EXPECT_CALL(*fs_, Destroy()).Times(1);
799     return 0;
800   }
801
802   ScopedRef<MockFs> fs() { return fs_; }
803
804  private:
805   ScopedRef<MockFs> fs_;
806 };
807
808 class KernelProxyErrorTest : public ::testing::Test {
809  public:
810   KernelProxyErrorTest() {}
811
812   void SetUp() {
813     ASSERT_EQ(0, ki_push_state_for_testing());
814     ASSERT_EQ(0, ki_init(&kp_));
815     // Unmount the passthrough FS and mount a testfs.
816     EXPECT_EQ(0, kp_.umount("/"));
817     EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
818   }
819
820   void TearDown() { ki_uninit(); }
821
822   ScopedRef<MockFs> fs() { return kp_.fs(); }
823
824  private:
825   KernelProxyErrorTest_KernelProxy kp_;
826 };
827
828 }  // namespace
829
830 TEST_F(KernelProxyErrorTest, WriteError) {
831   ScopedRef<MockFs> mock_fs(fs());
832   ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
833   EXPECT_CALL(*mock_fs, Open(_, _, _))
834       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
835
836   EXPECT_CALL(*mock_node, Write(_, _, _, _))
837       .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
838                       Return(1234)));       // Returned error 1234.
839
840   EXPECT_CALL(*mock_node, Destroy()).Times(1);
841
842   int fd = ki_open("/dummy", O_WRONLY);
843   EXPECT_NE(0, fd);
844
845   char buf[20];
846   EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
847   // The Filesystem should be able to return whatever error it wants and have it
848   // propagate through.
849   EXPECT_EQ(1234, errno);
850 }
851
852 TEST_F(KernelProxyErrorTest, ReadError) {
853   ScopedRef<MockFs> mock_fs(fs());
854   ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
855   EXPECT_CALL(*mock_fs, Open(_, _, _))
856       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
857
858   EXPECT_CALL(*mock_node, Read(_, _, _, _))
859       .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
860                       Return(1234)));       // Returned error 1234.
861
862   EXPECT_CALL(*mock_node, Destroy()).Times(1);
863
864   int fd = ki_open("/dummy", O_RDONLY);
865   EXPECT_NE(0, fd);
866
867   char buf[20];
868   EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
869   // The Filesystem should be able to return whatever error it wants and have it
870   // propagate through.
871   EXPECT_EQ(1234, errno);
872 }