1// Copyright 2013 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 <set> 9#include <string> 10 11#include "gtest/gtest.h" 12 13#include "nacl_io/devfs/dev_fs.h" 14#include "nacl_io/dir_node.h" 15#include "nacl_io/error.h" 16#include "nacl_io/ioctl.h" 17#include "nacl_io/kernel_handle.h" 18#include "nacl_io/kernel_proxy.h" 19#include "nacl_io/memfs/mem_fs.h" 20#include "nacl_io/memfs/mem_fs_node.h" 21#include "nacl_io/node.h" 22#include "nacl_io/osdirent.h" 23 24#define NULL_NODE ((Node*)NULL) 25 26using namespace nacl_io; 27 28static int s_alloc_num = 0; 29 30namespace { 31 32class MemFsForTesting : public MemFs { 33 public: 34 MemFsForTesting() { 35 FsInitArgs args(1); 36 EXPECT_EQ(0, Init(args)); 37 } 38 39 bool Exists(const char* filename) { 40 ScopedNode node; 41 if (Open(Path(filename), O_RDONLY, &node)) 42 return false; 43 44 struct stat buf; 45 return node->GetStat(&buf) == 0; 46 } 47 48 int num_nodes() { return inode_pool_.size(); } 49}; 50 51class MemFsNodeForTesting : public MemFsNode { 52 public: 53 MemFsNodeForTesting() : MemFsNode(NULL) { s_alloc_num++; } 54 55 ~MemFsNodeForTesting() { s_alloc_num--; } 56 57 using MemFsNode::Init; 58 using MemFsNode::AddChild; 59 using MemFsNode::RemoveChild; 60 using MemFsNode::FindChild; 61}; 62 63class DirNodeForTesting : public DirNode { 64 public: 65 DirNodeForTesting() : DirNode(NULL) { s_alloc_num++; } 66 67 ~DirNodeForTesting() { s_alloc_num--; } 68 69 using DirNode::Init; 70 using DirNode::AddChild; 71 using DirNode::RemoveChild; 72 using DirNode::FindChild; 73}; 74 75} // namespace 76 77TEST(MemFsNodeTest, File) { 78 MemFsNodeForTesting file; 79 ScopedNode result_node; 80 off_t result_size = 0; 81 int result_bytes = 0; 82 83 EXPECT_EQ(0, file.Init(0)); 84 85 // Test properties 86 EXPECT_EQ(0, file.GetLinks()); 87 EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode()); 88 EXPECT_EQ(S_IFREG, file.GetType()); 89 EXPECT_FALSE(file.IsaDir()); 90 EXPECT_TRUE(file.IsaFile()); 91 EXPECT_EQ(ENOTTY, file.Isatty()); 92 EXPECT_EQ(0, file.RefCount()); 93 94 // Test IO 95 char buf1[1024]; 96 char buf2[1024 * 2]; 97 for (size_t a = 0; a < sizeof(buf1); a++) 98 buf1[a] = a; 99 memset(buf2, 0, sizeof(buf2)); 100 HandleAttr attr; 101 102 EXPECT_EQ(0, file.GetSize(&result_size)); 103 EXPECT_EQ(0, result_size); 104 EXPECT_EQ(0, file.Read(attr, buf2, sizeof(buf2), &result_bytes)); 105 EXPECT_EQ(0, result_bytes); 106 EXPECT_EQ(0, file.GetSize(&result_size)); 107 EXPECT_EQ(0, result_size); 108 EXPECT_EQ(0, file.Write(attr, buf1, sizeof(buf1), &result_bytes)); 109 EXPECT_EQ(sizeof(buf1), result_bytes); 110 EXPECT_EQ(0, file.GetSize(&result_size)); 111 EXPECT_EQ(sizeof(buf1), result_size); 112 EXPECT_EQ(0, file.Read(attr, buf2, sizeof(buf2), &result_bytes)); 113 EXPECT_EQ(sizeof(buf1), result_bytes); 114 EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1))); 115 116 struct stat s; 117 EXPECT_EQ(0, file.GetStat(&s)); 118 EXPECT_LT(0, s.st_ino); // 0 is an invalid inode number. 119 EXPECT_EQ(sizeof(buf1), s.st_size); 120 121 // Directory operations should fail 122 struct dirent d; 123 EXPECT_EQ(ENOTDIR, file.GetDents(0, &d, sizeof(d), &result_bytes)); 124 EXPECT_EQ(ENOTDIR, file.AddChild("", result_node)); 125 EXPECT_EQ(ENOTDIR, file.RemoveChild("")); 126 EXPECT_EQ(ENOTDIR, file.FindChild("", &result_node)); 127 EXPECT_EQ(NULL_NODE, result_node.get()); 128} 129 130TEST(MemFsNodeTest, Fchmod) { 131 MemFsNodeForTesting file; 132 133 ASSERT_EQ(0, file.Init(0)); 134 EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode()); 135 136 struct stat s; 137 ASSERT_EQ(0, file.GetStat(&s)); 138 EXPECT_EQ(S_IFREG | S_IRALL | S_IWALL, s.st_mode); 139 140 // Change to read-only. 141 EXPECT_EQ(0, file.Fchmod(S_IRALL)); 142 143 EXPECT_EQ(S_IRALL, file.GetMode()); 144 145 ASSERT_EQ(0, file.GetStat(&s)); 146 EXPECT_EQ(S_IFREG | S_IRALL, s.st_mode); 147} 148 149TEST(MemFsNodeTest, FTruncate) { 150 MemFsNodeForTesting file; 151 off_t result_size = 0; 152 int result_bytes = 0; 153 154 char data[1024]; 155 char buffer[1024]; 156 char zero[1024]; 157 158 for (size_t a = 0; a < sizeof(data); a++) 159 data[a] = a; 160 memset(buffer, 0, sizeof(buffer)); 161 memset(zero, 0, sizeof(zero)); 162 HandleAttr attr; 163 164 // Write the data to the file. 165 ASSERT_EQ(0, file.Write(attr, data, sizeof(data), &result_bytes)); 166 ASSERT_EQ(sizeof(data), result_bytes); 167 168 // Double the size of the file. 169 EXPECT_EQ(0, file.FTruncate(sizeof(data) * 2)); 170 EXPECT_EQ(0, file.GetSize(&result_size)); 171 EXPECT_EQ(sizeof(data) * 2, result_size); 172 173 // Read the first half of the file, it shouldn't have changed. 174 EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes)); 175 EXPECT_EQ(sizeof(buffer), result_bytes); 176 EXPECT_EQ(0, memcmp(buffer, data, sizeof(buffer))); 177 178 // Read the second half of the file, it should be all zeroes. 179 attr.offs = sizeof(data); 180 EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes)); 181 EXPECT_EQ(sizeof(buffer), result_bytes); 182 EXPECT_EQ(0, memcmp(buffer, zero, sizeof(buffer))); 183 184 // Decrease the size of the file. 185 EXPECT_EQ(0, file.FTruncate(100)); 186 EXPECT_EQ(0, file.GetSize(&result_size)); 187 EXPECT_EQ(100, result_size); 188 189 // Data should still be there. 190 attr.offs = 0; 191 EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes)); 192 EXPECT_EQ(100, result_bytes); 193 EXPECT_EQ(0, memcmp(buffer, data, 100)); 194} 195 196TEST(MemFsNodeTest, Fcntl_GETFL) { 197 MemFsNodeForTesting* node = new MemFsNodeForTesting(); 198 ScopedFilesystem fs(new MemFsForTesting()); 199 ScopedNode file(node); 200 KernelHandle handle(fs, file); 201 ASSERT_EQ(0, handle.Init(O_CREAT | O_APPEND)); 202 203 // Test invalid fcntl command. 204 ASSERT_EQ(ENOSYS, handle.Fcntl(-1, NULL)); 205 206 // Test F_GETFL 207 ASSERT_EQ(0, node->Init(0)); 208 int flags = 0; 209 ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags)); 210 ASSERT_EQ(O_CREAT | O_APPEND, flags); 211 212 // Test F_SETFL 213 // Test adding of O_NONBLOCK 214 flags = O_NONBLOCK | O_APPEND; 215 ASSERT_EQ(0, handle.Fcntl(F_SETFL, NULL, flags)); 216 ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags)); 217 ASSERT_EQ(O_CREAT | O_APPEND | O_NONBLOCK, flags); 218 219 // Clearing of O_APPEND should generate EPERM; 220 flags = O_NONBLOCK; 221 ASSERT_EQ(EPERM, handle.Fcntl(F_SETFL, NULL, flags)); 222} 223 224TEST(MemFsNodeTest, Directory) { 225 s_alloc_num = 0; 226 DirNodeForTesting root; 227 ScopedNode result_node; 228 off_t result_size = 0; 229 int result_bytes = 0; 230 231 root.Init(0); 232 233 // Test properties 234 EXPECT_EQ(0, root.GetLinks()); 235 // Directories are always executable. 236 EXPECT_EQ(S_IRALL | S_IWALL | S_IXALL, root.GetMode()); 237 EXPECT_EQ(S_IFDIR, root.GetType()); 238 EXPECT_TRUE(root.IsaDir()); 239 EXPECT_FALSE(root.IsaFile()); 240 EXPECT_EQ(ENOTTY, root.Isatty()); 241 EXPECT_EQ(0, root.RefCount()); 242 243 // IO operations should fail 244 char buf1[1024]; 245 HandleAttr attr; 246 EXPECT_EQ(0, root.GetSize(&result_size)); 247 EXPECT_EQ(0, result_size); 248 EXPECT_EQ(EISDIR, root.Read(attr, buf1, sizeof(buf1), &result_bytes)); 249 EXPECT_EQ(EISDIR, root.Write(attr, buf1, sizeof(buf1), &result_bytes)); 250 251 // Chmod test 252 EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL)); 253 EXPECT_EQ(S_IRALL | S_IWALL, root.GetMode()); 254 // Change it back. 255 EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL | S_IXALL)); 256 257 // Test directory operations 258 MemFsNodeForTesting* raw_file = new MemFsNodeForTesting; 259 EXPECT_EQ(0, raw_file->Init(0)); 260 ScopedNode file(raw_file); 261 262 EXPECT_EQ(0, root.RefCount()); 263 EXPECT_EQ(1, file->RefCount()); 264 EXPECT_EQ(0, root.AddChild("F1", file)); 265 EXPECT_EQ(1, file->GetLinks()); 266 EXPECT_EQ(2, file->RefCount()); 267 268 // Test that the directory is there 269 const size_t kMaxDirents = 4; 270 struct dirent d[kMaxDirents]; 271 EXPECT_EQ(0, root.GetDents(0, &d[0], sizeof(d), &result_bytes)); 272 273 { 274 size_t num_dirents = result_bytes / sizeof(dirent); 275 EXPECT_EQ(3, num_dirents); 276 EXPECT_EQ(sizeof(dirent) * num_dirents, result_bytes); 277 278 std::multiset<std::string> dirnames; 279 for (int i = 0; i < num_dirents; ++i) { 280 EXPECT_LT(0, d[i].d_ino); // 0 is an invalid inode number. 281 EXPECT_EQ(sizeof(dirent), d[i].d_off); 282 EXPECT_EQ(sizeof(dirent), d[i].d_reclen); 283 dirnames.insert(d[i].d_name); 284 } 285 286 EXPECT_EQ(1, dirnames.count("F1")); 287 EXPECT_EQ(1, dirnames.count(".")); 288 EXPECT_EQ(1, dirnames.count("..")); 289 } 290 291 // There should only be 3 entries. Reading past that will return 0 bytes read. 292 EXPECT_EQ(0, root.GetDents(sizeof(d), &d[0], sizeof(d), &result_bytes)); 293 EXPECT_EQ(0, result_bytes); 294 295 EXPECT_EQ(0, root.AddChild("F2", file)); 296 EXPECT_EQ(2, file->GetLinks()); 297 EXPECT_EQ(3, file->RefCount()); 298 EXPECT_EQ(EEXIST, root.AddChild("F1", file)); 299 EXPECT_EQ(2, file->GetLinks()); 300 EXPECT_EQ(3, file->RefCount()); 301 302 EXPECT_EQ(2, s_alloc_num); 303 EXPECT_EQ(0, root.FindChild("F1", &result_node)); 304 EXPECT_NE(NULL_NODE, result_node.get()); 305 EXPECT_EQ(0, root.FindChild("F2", &result_node)); 306 EXPECT_NE(NULL_NODE, result_node.get()); 307 EXPECT_EQ(ENOENT, root.FindChild("F3", &result_node)); 308 EXPECT_EQ(NULL_NODE, result_node.get()); 309 310 EXPECT_EQ(2, s_alloc_num); 311 EXPECT_EQ(0, root.RemoveChild("F1")); 312 EXPECT_EQ(1, file->GetLinks()); 313 EXPECT_EQ(2, file->RefCount()); 314 EXPECT_EQ(0, root.RemoveChild("F2")); 315 EXPECT_EQ(0, file->GetLinks()); 316 EXPECT_EQ(1, file->RefCount()); 317 EXPECT_EQ(2, s_alloc_num); 318 319 file.reset(); 320 EXPECT_EQ(1, s_alloc_num); 321} 322 323TEST(MemFsNodeTest, OpenMode) { 324 MemFsNodeForTesting* node = new MemFsNodeForTesting(); 325 ScopedFilesystem fs(new MemFsForTesting()); 326 ScopedNode file(node); 327 328 const char write_buf[] = "hello world"; 329 char read_buf[10]; 330 int byte_count = 0; 331 332 // Write some data to the file 333 { 334 KernelHandle handle(fs, file); 335 ASSERT_EQ(0, handle.Init(O_CREAT | O_WRONLY)); 336 ASSERT_EQ(0, handle.Write(write_buf, strlen(write_buf), &byte_count)); 337 ASSERT_EQ(byte_count, strlen(write_buf)); 338 } 339 340 // Reading from the O_WRONLY handle should be impossible 341 { 342 byte_count = 0; 343 KernelHandle handle(fs, file); 344 ASSERT_EQ(0, handle.Init(O_WRONLY)); 345 ASSERT_EQ(EACCES, handle.Read(read_buf, 10, &byte_count)); 346 ASSERT_EQ(0, handle.Write(write_buf, strlen(write_buf), &byte_count)); 347 ASSERT_EQ(byte_count, strlen(write_buf)); 348 } 349 350 // Writing to a O_RDONLY handle should fail 351 { 352 byte_count = 0; 353 KernelHandle handle(fs, file); 354 ASSERT_EQ(0, handle.Init(O_RDONLY)); 355 ASSERT_EQ(EACCES, handle.Write(write_buf, strlen(write_buf), &byte_count)); 356 ASSERT_EQ(0, handle.Read(read_buf, sizeof(read_buf), &byte_count)); 357 ASSERT_EQ(byte_count, sizeof(read_buf)); 358 } 359} 360