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.
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
18 #include "mock_node.h"
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"
28 using namespace nacl_io
;
29 using namespace sdk_util
;
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
;
42 class KernelProxyTest_KernelProxy
: public KernelProxy
{
44 Filesystem
* RootFs() {
48 AcquireFsAndRelPath("/", &fs
, &path
);
53 class KernelProxyTest
: public ::testing::Test
{
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
));
65 void TearDown() { ki_uninit(); }
68 KernelProxyTest_KernelProxy kp_
;
73 static int ki_fcntl_wrapper(int fd
, int request
, ...) {
75 va_start(ap
, request
);
76 int rtn
= ki_fcntl(fd
, request
, ap
);
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.
87 TEST_F(KernelProxyTest
, Fcntl_GETFD
) {
88 int fd
= ki_open("/test", O_RDWR
| O_CREAT
);
91 // FD flags should start as zero.
92 ASSERT_EQ(0, ki_fcntl_wrapper(fd
, F_GETFD
));
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
));
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
);
106 TEST_F(KernelProxyTest
, FileLeak
) {
107 const size_t buffer_size
= 1024;
109 int garbage
[buffer_size
];
111 MemFs
* filesystem
= (MemFs
*)kp_
.RootFs();
114 ASSERT_EQ(0, filesystem
->Open(Path("/"), O_RDONLY
, &root
));
115 ASSERT_EQ(0, root
->ChildCount());
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
);
121 ASSERT_EQ(1, root
->ChildCount());
122 ASSERT_EQ(buffer_size
, ki_write(fd
, garbage
, buffer_size
));
124 ASSERT_EQ(0, ki_remove(filename
));
126 ASSERT_EQ(0, root
->ChildCount());
129 static bool g_handler_called
= false;
130 static void sighandler(int) { g_handler_called
= true; }
132 TEST_F(KernelProxyTest
, Sigaction
) {
133 struct sigaction action
;
134 struct sigaction oaction
;
135 memset(&action
, 0, sizeof(action
));
138 ASSERT_EQ(-1, ki_sigaction(-1, NULL
, &oaction
));
139 ASSERT_EQ(-1, ki_sigaction(SIGSTOP
, NULL
, &oaction
));
140 ASSERT_EQ(EINVAL
, errno
);
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
);
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
);
152 // Attempt to set handler for supported signum
153 action
.sa_handler
= sighandler
;
154 ASSERT_EQ(0, ki_sigaction(SIGWINCH
, &action
, NULL
));
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
);
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";
166 // Our implemenation should understand SIGWINCH
167 ASSERT_EQ(0, ki_kill(0, SIGWINCH
)) << "kill(SIGWINCH) failed: " << errno
;
170 ASSERT_EQ(0, ki_kill(0, SIGUSR1
)) << "kill(SIGUSR1) failed: " << errno
;
171 ASSERT_EQ(0, ki_kill(0, SIGUSR2
)) << "kill(SIGUSR2) failed: " << errno
;
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
));
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
);
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";
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";
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
));
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
));
212 TEST_F(KernelProxyTest
, SignalSigwinch
) {
213 g_handler_called
= false;
215 // Register WINCH handler
216 sighandler_t newsig
= sighandler
;
217 sighandler_t oldsig
= ki_signal(SIGWINCH
, newsig
);
218 ASSERT_NE(oldsig
, SIG_ERR
);
221 ki_kill(0, SIGWINCH
);
223 // Verify that handler was called
224 EXPECT_TRUE(g_handler_called
);
226 // Restore existing handler
227 oldsig
= ki_signal(SIGWINCH
, oldsig
);
229 // Verify the our newsig was returned as previous handler
230 ASSERT_EQ(oldsig
, newsig
);
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
));
239 // Test the renaming works
240 ASSERT_EQ(0, ki_rename("/test1.txt", "/test2.txt"));
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
);
248 TEST_F(KernelProxyTest
, WorkingDirectory
) {
252 ki_getcwd(text
, sizeof(text
));
253 EXPECT_STREQ("/", text
);
255 char* alloc
= ki_getwd(NULL
);
256 EXPECT_EQ((char*)NULL
, alloc
);
257 EXPECT_EQ(EFAULT
, errno
);
260 alloc
= ki_getwd(text
);
261 EXPECT_STREQ("/", alloc
);
263 EXPECT_EQ(-1, ki_chdir("/foo"));
264 EXPECT_EQ(ENOENT
, errno
);
266 EXPECT_EQ(0, ki_chdir("/"));
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
);
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
);
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
);
286 TEST_F(KernelProxyTest
, FDPathMapping
) {
289 int fd1
, fd2
, fd3
, fd4
, fd5
;
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
));
296 fd1
= ki_open("/example", O_RDONLY
);
298 EXPECT_EQ(ki_fchdir(fd1
), 0);
299 EXPECT_EQ(text
, ki_getcwd(text
, sizeof(text
)));
300 EXPECT_STREQ("/example", text
);
302 EXPECT_EQ(0, ki_chdir("/foo"));
303 fd2
= ki_open("../example", O_RDONLY
);
305 EXPECT_EQ(0, ki_fchdir(fd2
));
306 EXPECT_EQ(text
, ki_getcwd(text
, sizeof(text
)));
307 EXPECT_STREQ("/example", text
);
309 EXPECT_EQ(0, ki_chdir("/foo"));
310 fd3
= ki_open("../test", O_CREAT
| O_RDWR
);
312 EXPECT_EQ(-1, ki_fchdir(fd3
));
313 EXPECT_EQ(ENOTDIR
, errno
);
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
);
325 EXPECT_EQ(0, ki_chdir("/example"));
329 EXPECT_EQ(0, ki_fchdir(fd5
));
330 EXPECT_EQ(text
, ki_getcwd(text
, sizeof(text
)));
331 EXPECT_STREQ("/foo/bar", text
);
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
);
342 TEST_F(KernelProxyTest
, MemMountIO
) {
347 // Fail to delete non existant "/foo"
348 EXPECT_EQ(-1, ki_rmdir("/foo"));
349 EXPECT_EQ(ENOENT
, errno
);
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
);
357 EXPECT_EQ(0, ki_rmdir("/foo"));
360 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD
| S_IWRITE
));
362 // Fail to open "/foo/bar"
363 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY
));
364 EXPECT_EQ(ENOENT
, errno
);
366 // Create bar "/foo/bar"
367 fd1
= ki_open("/foo/bar", O_RDWR
| O_CREAT
);
370 // Open (optionally create) bar "/foo/bar"
371 fd2
= ki_open("/foo/bar", O_RDWR
| O_CREAT
);
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
);
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));
383 fd3
= ki_open("/foo/bar", O_RDONLY
);
386 len
= ki_read(fd3
, text
, sizeof(text
));
389 EXPECT_STREQ("HELLO", text
);
390 EXPECT_EQ(0, ki_close(fd1
));
391 EXPECT_EQ(0, ki_close(fd2
));
393 fd1
= ki_open("/foo/bar", O_WRONLY
| O_APPEND
);
395 EXPECT_EQ(5, ki_write(fd1
, "WORLD", 5));
397 len
= ki_read(fd3
, text
, sizeof(text
));
400 EXPECT_STREQ("WORLD", text
);
402 fd2
= ki_open("/foo/bar", O_RDONLY
);
404 len
= ki_read(fd2
, text
, sizeof(text
));
408 EXPECT_STREQ("HELLOWORLD", text
);
411 TEST_F(KernelProxyTest
, MemMountFTruncate
) {
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
);
420 fd2
= ki_open("/trunc", O_RDONLY
);
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
));
431 TEST_F(KernelProxyTest
, MemMountTruncate
) {
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
);
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
);
446 EXPECT_EQ(2, ki_read(fd1
, text
, sizeof(text
)));
447 EXPECT_EQ(0, ki_close(fd1
));
450 TEST_F(KernelProxyTest
, MemMountLseek
) {
451 int fd
= ki_open("/foo", O_CREAT
| O_RDWR
);
453 ASSERT_EQ(9, ki_write(fd
, "Some text", 9));
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
);
460 // Seek past end of file.
461 ASSERT_EQ(13, ki_lseek(fd
, 13, SEEK_SET
));
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));
470 TEST_F(KernelProxyTest
, CloseTwice
) {
471 int fd
= ki_open("/foo", O_CREAT
| O_RDWR
);
474 EXPECT_EQ(9, ki_write(fd
, "Some text", 9));
476 int fd2
= ki_dup(fd
);
479 EXPECT_EQ(0, ki_close(fd
));
480 EXPECT_EQ(0, ki_close(fd2
));
483 TEST_F(KernelProxyTest
, MemMountDup
) {
484 int fd
= ki_open("/foo", O_CREAT
| O_RDWR
);
487 int dup_fd
= ki_dup(fd
);
488 ASSERT_NE(-1, dup_fd
);
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
));
495 ASSERT_EQ(dup2_fd
, ki_dup2(fd
, dup2_fd
));
496 ASSERT_EQ(9, ki_lseek(dup2_fd
, 0, SEEK_CUR
));
498 int new_fd
= ki_open("/bar", O_CREAT
| O_RDWR
);
500 ASSERT_EQ(fd
, ki_dup2(new_fd
, fd
));
501 // fd, new_fd -> "/bar"
502 // dup_fd, dup2_fd -> "/foo"
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));
507 ASSERT_EQ(0, ki_close(dup2_fd
));
508 // fd, new_fd -> "/bar"
511 ASSERT_EQ(dup_fd
, ki_dup2(fd
, dup_fd
));
512 // fd, new_fd, dup_fd -> "/bar"
515 TEST_F(KernelProxyTest
, Lstat
) {
516 int fd
= ki_open("/foo", O_CREAT
| O_RDWR
);
518 ASSERT_EQ(0, ki_mkdir("/bar", S_IREAD
| S_IWRITE
));
521 EXPECT_EQ(0, ki_lstat("/foo", &buf
));
522 EXPECT_EQ(0, buf
.st_size
);
523 EXPECT_TRUE(S_ISREG(buf
.st_mode
));
525 EXPECT_EQ(0, ki_lstat("/bar", &buf
));
526 EXPECT_EQ(0, buf
.st_size
);
527 EXPECT_TRUE(S_ISDIR(buf
.st_mode
));
529 EXPECT_EQ(-1, ki_lstat("/no-such-file", &buf
));
530 EXPECT_EQ(ENOENT
, errno
);
533 TEST_F(KernelProxyTest
, UseAfterClose
) {
534 int fd
= ki_open("/dummy", O_CREAT
| O_WRONLY
);
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
);
544 StringMap_t g_string_map
;
545 bool g_fs_ioctl_called
;
548 class KernelProxyMountTest_Filesystem
: public MemFs
{
550 virtual Error
Init(const FsInitArgs
& args
) {
553 g_string_map
= args
.string_map
;
556 if (g_string_map
.find("false") != g_string_map
.end())
561 virtual Error
Filesystem_VIoctl(int request
, va_list arglist
) {
562 g_fs_ioctl_called
= true;
566 friend class TypedFsFactory
<KernelProxyMountTest_Filesystem
>;
569 class KernelProxyMountTest_KernelProxy
: public KernelProxy
{
570 virtual Error
Init(PepperInterface
* ppapi
) {
571 KernelProxy::Init(NULL
);
572 factories_
["initfs"] = new TypedFsFactory
<KernelProxyMountTest_Filesystem
>;
577 class KernelProxyMountTest
: public ::testing::Test
{
579 KernelProxyMountTest() {}
582 g_string_map
.clear();
584 g_fs_ioctl_called
= false;
586 ASSERT_EQ(0, ki_push_state_for_testing());
587 ASSERT_EQ(0, ki_init(&kp_
));
591 g_string_map
.clear();
596 KernelProxyMountTest_KernelProxy kp_
;
599 // Helper function for calling ki_ioctl without having
600 // to construct a va_list.
601 int ki_ioctl_wrapper(int fd
, int request
, ...) {
603 va_start(ap
, request
);
604 int rtn
= ki_ioctl(fd
, request
, ap
);
611 TEST_F(KernelProxyMountTest
, MountInit
) {
612 int res1
= ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
614 EXPECT_EQ("bar", g_string_map
["foo"]);
616 EXPECT_EQ(EINVAL
, errno
);
618 int res2
= ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
620 EXPECT_EQ("y", g_string_map
["x"]);
623 TEST_F(KernelProxyMountTest
, MountAndIoctl
) {
624 ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, ""));
625 ASSERT_NE(-1, g_fs_dev
);
628 snprintf(path
, 100, "dev/fs/%d", g_fs_dev
);
630 int fd
= ki_open(path
, O_RDONLY
);
633 EXPECT_EQ(0, ki_ioctl_wrapper(fd
, 0xdeadbeef));
634 EXPECT_EQ(true, g_fs_ioctl_called
);
637 static void mount_callback(const char* source
,
639 const char* filesystemtype
,
640 unsigned long mountflags
,
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
);
651 bool* callback_called
= static_cast<bool*>(user_data
);
652 *callback_called
= true;
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
);
667 class KernelProxyMMapTest_Node
: public Node
{
669 KernelProxyMMapTest_Node(Filesystem
* filesystem
)
670 : Node(filesystem
), node_mmap_count_(0) {
671 EXPECT_EQ(0, Init(0));
674 virtual Error
MMap(void* addr
,
681 switch (g_MMapCount
++) {
683 *out_addr
= reinterpret_cast<void*>(0x1000);
686 *out_addr
= reinterpret_cast<void*>(0x2000);
689 *out_addr
= reinterpret_cast<void*>(0x3000);
699 int node_mmap_count_
;
702 class KernelProxyMMapTest_Filesystem
: public Filesystem
{
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));
710 virtual Error
OpenResource(const Path
& path
, ScopedNode
* out_node
) {
711 out_node
->reset(NULL
);
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
; }
720 friend class TypedFsFactory
<KernelProxyMMapTest_Filesystem
>;
723 class KernelProxyMMapTest_KernelProxy
: public KernelProxy
{
724 virtual Error
Init(PepperInterface
* ppapi
) {
725 KernelProxy::Init(NULL
);
726 factories_
["mmapfs"] = new TypedFsFactory
<KernelProxyMMapTest_Filesystem
>;
731 class KernelProxyMMapTest
: public ::testing::Test
{
733 KernelProxyMMapTest() {}
736 ASSERT_EQ(0, ki_push_state_for_testing());
737 ASSERT_EQ(0, ki_init(&kp_
));
740 void TearDown() { ki_uninit(); }
743 KernelProxyMMapTest_KernelProxy kp_
;
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
);
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
);
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
);
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
);
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
);
776 class SingletonFsFactory
: public FsFactory
{
778 SingletonFsFactory(const ScopedFilesystem
& filesystem
) : mount_(filesystem
) {}
780 virtual Error
CreateFilesystem(const FsInitArgs
& args
,
781 ScopedFilesystem
* out_fs
) {
787 ScopedFilesystem mount_
;
790 class KernelProxyErrorTest_KernelProxy
: public KernelProxy
{
792 KernelProxyErrorTest_KernelProxy() : fs_(new MockFs
) {}
794 virtual Error
Init(PepperInterface
* ppapi
) {
795 KernelProxy::Init(ppapi
);
796 factories_
["testfs"] = new SingletonFsFactory(fs_
);
798 EXPECT_CALL(*fs_
, Destroy()).Times(1);
802 ScopedRef
<MockFs
> fs() { return fs_
; }
805 ScopedRef
<MockFs
> fs_
;
808 class KernelProxyErrorTest
: public ::testing::Test
{
810 KernelProxyErrorTest() {}
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
));
820 void TearDown() { ki_uninit(); }
822 ScopedRef
<MockFs
> fs() { return kp_
.fs(); }
825 KernelProxyErrorTest_KernelProxy kp_
;
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)));
836 EXPECT_CALL(*mock_node
, Write(_
, _
, _
, _
))
837 .WillOnce(DoAll(SetArgPointee
<3>(0), // Wrote 0 bytes.
838 Return(1234))); // Returned error 1234.
840 EXPECT_CALL(*mock_node
, Destroy()).Times(1);
842 int fd
= ki_open("/dummy", O_WRONLY
);
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
);
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)));
858 EXPECT_CALL(*mock_node
, Read(_
, _
, _
, _
))
859 .WillOnce(DoAll(SetArgPointee
<3>(0), // Read 0 bytes.
860 Return(1234))); // Returned error 1234.
862 EXPECT_CALL(*mock_node
, Destroy()).Times(1);
864 int fd
= ki_open("/dummy", O_RDONLY
);
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
);