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"
17 #include "mount_mock.h"
18 #include "mount_node_mock.h"
20 #include "nacl_io/kernel_intercept.h"
21 #include "nacl_io/kernel_proxy.h"
22 #include "nacl_io/mount.h"
23 #include "nacl_io/mount_mem.h"
24 #include "nacl_io/osmman.h"
25 #include "nacl_io/path.h"
26 #include "nacl_io/typed_mount_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 KernelProxyFriend : public KernelProxy {
48 AcquireMountAndRelPath("/", &mnt, &path);
53 class KernelProxyTest : public ::testing::Test {
59 // Unmount the passthrough FS and mount a memfs.
60 EXPECT_EQ(0, kp_.umount("/"));
61 EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
69 KernelProxyFriend kp_;
74 static int ki_fcntl_wrapper(int fd, int request, ...) {
76 va_start(ap, request);
77 int rtn = ki_fcntl(fd, request, ap);
83 * Test for fcntl commands F_SETFD and F_GETFD. This
84 * is tested here rather than in the mount_node tests
85 * since the fd flags are not stored in the kernel_handle
86 * or the mount node but directly in the FD mapping.
88 TEST_F(KernelProxyTest, Fcntl_GETFD) {
89 int fd = ki_open("/test", O_RDWR | O_CREAT);
92 // FD flags should start as zero.
93 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD));
95 // Check that setting FD_CLOEXEC works
96 int flags = FD_CLOEXEC;
97 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags))
98 << "fcntl failed with: " << strerror(errno);
99 ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD));
101 // Check that setting invalid flag causes EINVAL
102 flags = FD_CLOEXEC + 1;
103 ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags));
104 ASSERT_EQ(EINVAL, errno);
107 TEST_F(KernelProxyTest, FileLeak) {
108 const size_t buffer_size = 1024;
110 int garbage[buffer_size];
112 MountMem* mount = (MountMem*)kp_.RootMount();
113 ScopedMountNode root;
115 ASSERT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
116 ASSERT_EQ(0, root->ChildCount());
118 for (int file_num = 0; file_num < 4096; file_num++) {
119 sprintf(filename, "/foo%i.tmp", file_num++);
120 FILE* f = fopen(filename, "w");
121 ASSERT_NE((FILE*)NULL, f);
122 ASSERT_EQ(1, root->ChildCount());
123 ASSERT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
125 ASSERT_EQ(0, remove(filename));
127 ASSERT_EQ(0, root->ChildCount());
130 TEST_F(KernelProxyTest, WorkingDirectory) {
134 ki_getcwd(text, sizeof(text));
135 EXPECT_STREQ("/", text);
137 char* alloc = ki_getwd(NULL);
138 EXPECT_EQ((char*)NULL, alloc);
139 EXPECT_EQ(EFAULT, errno);
142 alloc = ki_getwd(text);
143 EXPECT_STREQ("/", alloc);
145 EXPECT_EQ(-1, ki_chdir("/foo"));
146 EXPECT_EQ(ENOENT, errno);
148 EXPECT_EQ(0, ki_chdir("/"));
150 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
151 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
152 EXPECT_EQ(EEXIST, errno);
154 memset(text, 0, sizeof(text));
155 EXPECT_EQ(0, ki_chdir("foo"));
156 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
157 EXPECT_STREQ("/foo", text);
159 memset(text, 0, sizeof(text));
160 EXPECT_EQ(-1, ki_chdir("foo"));
161 EXPECT_EQ(ENOENT, errno);
162 EXPECT_EQ(0, ki_chdir(".."));
163 EXPECT_EQ(0, ki_chdir("/foo"));
164 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
165 EXPECT_STREQ("/foo", text);
168 TEST_F(KernelProxyTest, MemMountIO) {
173 // Fail to delete non existant "/foo"
174 EXPECT_EQ(-1, ki_rmdir("/foo"));
175 EXPECT_EQ(ENOENT, errno);
178 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
179 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
180 EXPECT_EQ(EEXIST, errno);
183 EXPECT_EQ(0, ki_rmdir("/foo"));
186 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
188 // Fail to open "/foo/bar"
189 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY));
190 EXPECT_EQ(ENOENT, errno);
192 // Create bar "/foo/bar"
193 fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT);
196 // Open (optionally create) bar "/foo/bar"
197 fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT);
200 // Fail to exclusively create bar "/foo/bar"
201 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL));
202 EXPECT_EQ(EEXIST, errno);
204 // Write hello and world to same node with different descriptors
205 // so that we overwrite each other
206 EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
207 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
209 fd3 = ki_open("/foo/bar", O_RDONLY);
212 len = ki_read(fd3, text, sizeof(text));
215 EXPECT_STREQ("HELLO", text);
216 EXPECT_EQ(0, ki_close(fd1));
217 EXPECT_EQ(0, ki_close(fd2));
219 fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
221 EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
223 len = ki_read(fd3, text, sizeof(text));
226 EXPECT_STREQ("WORLD", text);
228 fd2 = ki_open("/foo/bar", O_RDONLY);
230 len = ki_read(fd2, text, sizeof(text));
234 EXPECT_STREQ("HELLOWORLD", text);
237 TEST_F(KernelProxyTest, MemMountLseek) {
238 int fd = ki_open("/foo", O_CREAT | O_RDWR);
240 EXPECT_EQ(9, ki_write(fd, "Some text", 9));
242 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
243 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END));
244 EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
245 EXPECT_EQ(EINVAL, errno);
247 // Seek past end of file.
248 EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
250 memset(&buffer[0], 0xfe, 4);
251 EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
252 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
253 EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
254 EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
257 TEST_F(KernelProxyTest, CloseTwice) {
258 int fd = ki_open("/foo", O_CREAT | O_RDWR);
261 EXPECT_EQ(9, ki_write(fd, "Some text", 9));
263 int fd2 = ki_dup(fd);
266 EXPECT_EQ(0, ki_close(fd));
267 EXPECT_EQ(0, ki_close(fd2));
270 TEST_F(KernelProxyTest, MemMountDup) {
271 int fd = ki_open("/foo", O_CREAT | O_RDWR);
274 int dup_fd = ki_dup(fd);
275 ASSERT_NE(-1, dup_fd);
277 ASSERT_EQ(9, ki_write(fd, "Some text", 9));
278 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
279 ASSERT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
282 ASSERT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
283 ASSERT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
285 int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
287 ASSERT_EQ(fd, ki_dup2(new_fd, fd));
288 // fd, new_fd -> "/bar"
289 // dup_fd, dup2_fd -> "/foo"
291 // We should still be able to write to dup_fd (i.e. it should not be closed).
292 ASSERT_EQ(4, ki_write(dup_fd, "more", 4));
294 ASSERT_EQ(0, ki_close(dup2_fd));
295 // fd, new_fd -> "/bar"
298 ASSERT_EQ(dup_fd, ki_dup2(fd, dup_fd));
299 // fd, new_fd, dup_fd -> "/bar"
304 StringMap_t g_StringMap;
306 class MountMockInit : public MountMem {
308 virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
310 if (args.find("false") != args.end())
315 friend class TypedMountFactory<MountMockInit>;
318 class KernelProxyMountMock : public KernelProxy {
319 virtual Error Init(PepperInterface* ppapi) {
320 KernelProxy::Init(NULL);
321 factories_["initfs"] = new TypedMountFactory<MountMockInit>;
326 class KernelProxyMountTest : public ::testing::Test {
328 KernelProxyMountTest() {}
339 KernelProxyMountMock kp_;
344 TEST_F(KernelProxyMountTest, MountInit) {
345 int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
347 EXPECT_EQ("bar", g_StringMap["foo"]);
349 EXPECT_EQ(EINVAL, errno);
351 int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
353 EXPECT_EQ("y", g_StringMap["x"]);
360 class MountNodeMockMMap : public MountNode {
362 MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
363 EXPECT_EQ(0, Init(0));
366 virtual Error MMap(void* addr,
373 switch (g_MMapCount++) {
375 *out_addr = reinterpret_cast<void*>(0x1000);
378 *out_addr = reinterpret_cast<void*>(0x2000);
381 *out_addr = reinterpret_cast<void*>(0x3000);
391 int node_mmap_count_;
394 class MountMockMMap : public Mount {
396 virtual Error Access(const Path& path, int a_mode) { return 0; }
397 virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
398 out_node->reset(new MountNodeMockMMap(this));
402 virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
403 out_node->reset(NULL);
406 virtual Error Unlink(const Path& path) { return ENOSYS; }
407 virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
408 virtual Error Rmdir(const Path& path) { return ENOSYS; }
409 virtual Error Remove(const Path& path) { return ENOSYS; }
411 friend class TypedMountFactory<MountMockMMap>;
414 class KernelProxyMockMMap : public KernelProxy {
415 virtual Error Init(PepperInterface* ppapi) {
416 KernelProxy::Init(NULL);
417 factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
422 class KernelProxyMMapTest : public ::testing::Test {
424 KernelProxyMMapTest() {}
435 KernelProxyMockMMap kp_;
440 TEST_F(KernelProxyMMapTest, MMap) {
441 ASSERT_EQ(0, ki_umount("/"));
442 ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
443 int fd = ki_open("/file", O_RDWR | O_CREAT);
446 void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
447 ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1);
448 ASSERT_EQ(1, g_MMapCount);
450 void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
451 ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2);
452 ASSERT_EQ(2, g_MMapCount);
454 void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
455 ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3);
456 ASSERT_EQ(3, g_MMapCount);
460 // We no longer track mmap'd regions, so munmap is a no-op.
461 ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
462 // We don't track regions, so the mmap count hasn't changed.
463 ASSERT_EQ(3, g_MMapCount);
468 class SingletonMountFactory : public MountFactory {
470 SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
472 virtual Error CreateMount(int dev,
474 PepperInterface* ppapi,
475 ScopedMount* out_mount) {
484 class KernelProxyError : public KernelProxy {
486 KernelProxyError() : mnt_(new MountMock) {}
488 virtual Error Init(PepperInterface* ppapi) {
489 KernelProxy::Init(ppapi);
490 factories_["testfs"] = new SingletonMountFactory(mnt_);
492 EXPECT_CALL(*mnt_, Destroy()).Times(1);
496 ScopedRef<MountMock> mnt() { return mnt_; }
499 ScopedRef<MountMock> mnt_;
502 class KernelProxyErrorTest : public ::testing::Test {
504 KernelProxyErrorTest() {}
508 // Unmount the passthrough FS and mount a testfs.
509 EXPECT_EQ(0, kp_.umount("/"));
510 EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
517 ScopedRef<MountMock> mnt() { return kp_.mnt(); }
520 KernelProxyError kp_;
525 TEST_F(KernelProxyErrorTest, WriteError) {
526 ScopedRef<MountMock> mock_mnt(mnt());
527 ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
528 EXPECT_CALL(*mock_mnt, Open(_, _, _))
529 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
531 EXPECT_CALL(*mock_node, Write(_, _, _, _))
532 .WillOnce(DoAll(SetArgPointee<3>(0), // Wrote 0 bytes.
533 Return(1234))); // Returned error 1234.
535 EXPECT_CALL(*mock_node, Destroy()).Times(1);
537 int fd = ki_open("/dummy", O_WRONLY);
541 EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
542 // The Mount should be able to return whatever error it wants and have it
543 // propagate through.
544 EXPECT_EQ(1234, errno);
547 TEST_F(KernelProxyErrorTest, ReadError) {
548 ScopedRef<MountMock> mock_mnt(mnt());
549 ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
550 EXPECT_CALL(*mock_mnt, Open(_, _, _))
551 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
553 EXPECT_CALL(*mock_node, Read(_, _, _, _))
554 .WillOnce(DoAll(SetArgPointee<3>(0), // Read 0 bytes.
555 Return(1234))); // Returned error 1234.
557 EXPECT_CALL(*mock_node, Destroy()).Times(1);
559 int fd = ki_open("/dummy", O_RDONLY);
563 EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
564 // The Mount should be able to return whatever error it wants and have it
565 // propagate through.
566 EXPECT_EQ(1234, errno);