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 8#include "nacl_io/error.h" 9#include "nacl_io/ioctl.h" 10#include "nacl_io/kernel_proxy.h" 11#include "nacl_io/mount_dev.h" 12#include "nacl_io/mount_node.h" 13#include "nacl_io/mount_node_dir.h" 14#include "nacl_io/mount_node_mem.h" 15#include "nacl_io/osdirent.h" 16 17#include "gtest/gtest.h" 18 19#define NULL_NODE ((MountNode*) NULL) 20 21using namespace nacl_io; 22 23static int s_AllocNum = 0; 24 25class MockMemory : public MountNodeMem { 26 public: 27 MockMemory() : MountNodeMem(NULL) { s_AllocNum++; } 28 29 ~MockMemory() { s_AllocNum--; } 30 31 Error Init(int mode) { return MountNodeMem::Init(mode); } 32 Error AddChild(const std::string& name, const ScopedMountNode& node) { 33 return MountNodeMem::AddChild(name, node); 34 } 35 Error RemoveChild(const std::string& name) { 36 return MountNodeMem::RemoveChild(name); 37 } 38 Error FindChild(const std::string& name, ScopedMountNode* out_node) { 39 return MountNodeMem::FindChild(name, out_node); 40 } 41 void Link() { MountNodeMem::Link(); } 42 void Unlink() { MountNodeMem::Unlink(); } 43 44 protected: 45 using MountNodeMem::Init; 46}; 47 48class MockDir : public MountNodeDir { 49 public: 50 MockDir() : MountNodeDir(NULL) { s_AllocNum++; } 51 52 ~MockDir() { s_AllocNum--; } 53 54 Error Init(int mode) { return MountNodeDir::Init(mode); } 55 Error AddChild(const std::string& name, const ScopedMountNode& node) { 56 return MountNodeDir::AddChild(name, node); 57 } 58 Error RemoveChild(const std::string& name) { 59 return MountNodeDir::RemoveChild(name); 60 } 61 Error FindChild(const std::string& name, ScopedMountNode* out_node) { 62 return MountNodeDir::FindChild(name, out_node); 63 } 64 void Link() { MountNodeDir::Link(); } 65 void Unlink() { MountNodeDir::Unlink(); } 66 67 protected: 68 using MountNodeDir::Init; 69}; 70 71TEST(MountNodeTest, File) { 72 MockMemory* file = new MockMemory; 73 ScopedMountNode result_node; 74 size_t result_size = 0; 75 int result_bytes = 0; 76 77 EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE)); 78 79 // Test properties 80 EXPECT_EQ(0, file->GetLinks()); 81 EXPECT_EQ(S_IREAD | S_IWRITE, file->GetMode()); 82 EXPECT_EQ(S_IFREG, file->GetType()); 83 EXPECT_FALSE(file->IsaDir()); 84 EXPECT_TRUE(file->IsaFile()); 85 EXPECT_FALSE(file->IsaTTY()); 86 EXPECT_EQ(0, file->RefCount()); 87 88 // Test IO 89 char buf1[1024]; 90 char buf2[1024 * 2]; 91 for (size_t a = 0; a < sizeof(buf1); a++) 92 buf1[a] = a; 93 memset(buf2, 0, sizeof(buf2)); 94 95 EXPECT_EQ(0, file->GetSize(&result_size)); 96 EXPECT_EQ(0, result_size); 97 EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes)); 98 EXPECT_EQ(0, result_bytes); 99 EXPECT_EQ(0, file->GetSize(&result_size)); 100 EXPECT_EQ(0, result_size); 101 EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes)); 102 EXPECT_EQ(sizeof(buf1), result_bytes); 103 EXPECT_EQ(0, file->GetSize(&result_size)); 104 EXPECT_EQ(sizeof(buf1), result_size); 105 EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes)); 106 EXPECT_EQ(sizeof(buf1), result_bytes); 107 EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1))); 108 109 struct stat s; 110 EXPECT_EQ(0, file->GetStat(&s)); 111 EXPECT_LT(0, s.st_ino); // 0 is an invalid inode number. 112 EXPECT_EQ(sizeof(buf1), s.st_size); 113 114 // Directory operations should fail 115 struct dirent d; 116 EXPECT_EQ(ENOTDIR, file->GetDents(0, &d, sizeof(d), &result_bytes)); 117 EXPECT_EQ(ENOTDIR, file->AddChild("", result_node)); 118 EXPECT_EQ(ENOTDIR, file->RemoveChild("")); 119 EXPECT_EQ(ENOTDIR, file->FindChild("", &result_node)); 120 EXPECT_EQ(NULL_NODE, result_node.get()); 121 122 delete file; 123} 124 125TEST(MountNodeTest, Directory) { 126 MockDir* root = new MockDir(); 127 ScopedMountNode result_node; 128 size_t result_size = 0; 129 int result_bytes = 0; 130 131 root->Init(S_IREAD | S_IWRITE); 132 133 // Test properties 134 EXPECT_EQ(0, root->GetLinks()); 135 EXPECT_EQ(S_IREAD | S_IWRITE, root->GetMode()); 136 EXPECT_EQ(S_IFDIR, root->GetType()); 137 EXPECT_TRUE(root->IsaDir()); 138 EXPECT_FALSE(root->IsaFile()); 139 EXPECT_FALSE(root->IsaTTY()); 140 EXPECT_EQ(0, root->RefCount()); 141 142 // IO operations should fail 143 char buf1[1024]; 144 EXPECT_EQ(0, root->GetSize(&result_size)); 145 EXPECT_EQ(0, result_size); 146 EXPECT_EQ(EISDIR, root->Read(0, buf1, sizeof(buf1), &result_bytes)); 147 EXPECT_EQ(EISDIR, root->Write(0, buf1, sizeof(buf1), &result_bytes)); 148 149 // Test directory operations 150 MockMemory* raw_file = new MockMemory; 151 EXPECT_EQ(0, raw_file->Init(S_IREAD | S_IWRITE)); 152 ScopedMountNode file(raw_file); 153 154 EXPECT_EQ(0, root->RefCount()); 155 EXPECT_EQ(1, file->RefCount()); 156 EXPECT_EQ(0, root->AddChild("F1", file)); 157 EXPECT_EQ(1, file->GetLinks()); 158 EXPECT_EQ(2, file->RefCount()); 159 160 // Test that the directory is there 161 struct dirent d; 162 EXPECT_EQ(0, root->GetDents(0, &d, sizeof(d), &result_bytes)); 163 EXPECT_EQ(sizeof(d), result_bytes); 164 EXPECT_LT(0, d.d_ino); // 0 is an invalid inode number. 165 EXPECT_EQ(sizeof(d), d.d_off); 166 EXPECT_EQ(sizeof(d), d.d_reclen); 167 EXPECT_EQ(0, strcmp("F1", d.d_name)); 168 EXPECT_EQ(0, root->GetDents(sizeof(d), &d, sizeof(d), &result_bytes)); 169 EXPECT_EQ(0, result_bytes); 170 171 EXPECT_EQ(0, root->AddChild("F2", file)); 172 EXPECT_EQ(2, file->GetLinks()); 173 EXPECT_EQ(3, file->RefCount()); 174 EXPECT_EQ(EEXIST, root->AddChild("F1", file)); 175 EXPECT_EQ(2, file->GetLinks()); 176 EXPECT_EQ(3, file->RefCount()); 177 178 EXPECT_EQ(2, s_AllocNum); 179 EXPECT_EQ(0, root->FindChild("F1", &result_node)); 180 EXPECT_NE(NULL_NODE, result_node.get()); 181 EXPECT_EQ(0, root->FindChild("F2", &result_node)); 182 EXPECT_NE(NULL_NODE, result_node.get()); 183 EXPECT_EQ(ENOENT, root->FindChild("F3", &result_node)); 184 EXPECT_EQ(NULL_NODE, result_node.get()); 185 186 EXPECT_EQ(2, s_AllocNum); 187 EXPECT_EQ(0, root->RemoveChild("F1")); 188 EXPECT_EQ(1, file->GetLinks()); 189 EXPECT_EQ(2, file->RefCount()); 190 EXPECT_EQ(0, root->RemoveChild("F2")); 191 EXPECT_EQ(0, file->GetLinks()); 192 EXPECT_EQ(1, file->RefCount()); 193 EXPECT_EQ(2, s_AllocNum); 194 195 file.reset(); 196 EXPECT_EQ(1, s_AllocNum); 197} 198