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 #include <string.h> 8 #include <sys/stat.h> 9 #include <string> 10 11 #include "dev_fs_for_testing.h" 12 #include "gtest/gtest.h" 13 #include "nacl_io/filesystem.h" 14 #include "nacl_io/ioctl.h" 15 #include "nacl_io/kernel_handle.h" 16 #include "nacl_io/memfs/mem_fs.h" 17 #include "nacl_io/osdirent.h" 18 #include "nacl_io/osunistd.h" 19 20 using namespace nacl_io; 21 22 namespace { 23 24 class MemFsForTesting : public MemFs { 25 public: 26 MemFsForTesting() { 27 FsInitArgs args(1); 28 EXPECT_EQ(0, Init(args)); 29 } 30 31 bool Exists(const char* filename) { 32 ScopedNode node; 33 if (Open(Path(filename), O_RDONLY, &node)) 34 return false; 35 36 struct stat buf; 37 return node->GetStat(&buf) == 0; 38 } 39 40 int num_nodes() { return (int)inode_pool_.size(); } 41 }; 42 43 } // namespace 44 45 TEST(FilesystemTest, Sanity) { 46 MemFsForTesting fs; 47 48 ScopedNode file; 49 ScopedNode root; 50 ScopedNode result_node; 51 52 off_t result_size = 0; 53 int result_bytes = 0; 54 struct stat buf; 55 char buf1[1024]; 56 57 // A memory filesystem starts with one directory node: the root. 58 EXPECT_EQ(1, fs.num_nodes()); 59 60 // Fail to open non existent file 61 EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDWR, &result_node)); 62 EXPECT_EQ(NULL, result_node.get()); 63 EXPECT_EQ(1, fs.num_nodes()); 64 65 // Create a file 66 EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &file)); 67 ASSERT_NE(NULL_NODE, file.get()); 68 69 // We now have a directory and a file. The file has a two references 70 // one returned to the test, one for the name->inode map. 71 ASSERT_EQ(2, fs.num_nodes()); 72 ASSERT_EQ(2, file->RefCount()); 73 ASSERT_EQ(0, file->GetStat(&buf)); 74 ASSERT_EQ(0, buf.st_mode & S_IXUSR); 75 76 // All access should be allowed on the root directory. 77 EXPECT_EQ(0, fs.Open(Path("/"), O_RDONLY, &root)); 78 ASSERT_EQ(0, root->GetStat(&buf)); 79 ASSERT_EQ(S_IRWXU, buf.st_mode & S_IRWXU); 80 // Opening a directory for write should fail. 81 EXPECT_EQ(EISDIR, fs.Open(Path("/"), O_RDWR, &root)); 82 EXPECT_EQ(2, fs.num_nodes()); 83 84 // Open the root directory, should not create a new file 85 EXPECT_EQ(0, fs.Open(Path("/"), O_RDONLY, &root)); 86 EXPECT_EQ(2, fs.num_nodes()); 87 ASSERT_NE(NULL_NODE, root.get()); 88 struct dirent dirs[4]; 89 int len; 90 EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len)); 91 // 3 == "foo", ".", ".." 92 EXPECT_EQ(3 * sizeof(struct dirent), len); 93 94 // Fail to re-create the same file 95 EXPECT_EQ(EEXIST, 96 fs.Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node)); 97 EXPECT_EQ(NULL_NODE, result_node.get()); 98 EXPECT_EQ(2, fs.num_nodes()); 99 100 // Fail to create a directory with the same name 101 EXPECT_EQ(EEXIST, fs.Mkdir(Path("/foo"), O_RDWR)); 102 EXPECT_EQ(2, fs.num_nodes()); 103 104 HandleAttr attrs; 105 106 // Attempt to READ/WRITE 107 EXPECT_EQ(0, file->GetSize(&result_size)); 108 EXPECT_EQ(0, result_size); 109 EXPECT_EQ(0, file->Write(attrs, buf1, sizeof(buf1), &result_bytes)); 110 EXPECT_EQ(sizeof(buf1), result_bytes); 111 EXPECT_EQ(0, file->GetSize(&result_size)); 112 EXPECT_EQ(sizeof(buf1), result_size); 113 EXPECT_EQ(0, file->Read(attrs, buf1, sizeof(buf1), &result_bytes)); 114 EXPECT_EQ(sizeof(buf1), result_bytes); 115 EXPECT_EQ(2, fs.num_nodes()); 116 EXPECT_EQ(2, file->RefCount()); 117 118 // Attempt to open the same file, create another ref to it, but does not 119 // create a new file. 120 EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &result_node)); 121 EXPECT_EQ(3, file->RefCount()); 122 EXPECT_EQ(2, fs.num_nodes()); 123 EXPECT_EQ(file.get(), result_node.get()); 124 EXPECT_EQ(0, file->GetSize(&result_size)); 125 EXPECT_EQ(sizeof(buf1), result_size); 126 127 // Remove our references so that only the Filesystem holds it 128 file.reset(); 129 result_node.reset(); 130 EXPECT_EQ(2, fs.num_nodes()); 131 132 // This should have deleted the object 133 EXPECT_EQ(0, fs.Unlink(Path("/foo"))); 134 EXPECT_EQ(1, fs.num_nodes()); 135 136 // We should fail to find it 137 EXPECT_EQ(ENOENT, fs.Unlink(Path("/foo"))); 138 EXPECT_EQ(1, fs.num_nodes()); 139 140 // Recreate foo as a directory 141 EXPECT_EQ(0, fs.Mkdir(Path("/foo"), O_RDWR)); 142 EXPECT_EQ(2, fs.num_nodes()); 143 144 // Create a file (exclusively) 145 EXPECT_EQ(0, fs.Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file)); 146 ASSERT_NE(NULL_NODE, file.get()); 147 EXPECT_EQ(2, file->RefCount()); 148 EXPECT_EQ(3, fs.num_nodes()); 149 150 // Attempt to delete the directory and fail 151 EXPECT_EQ(ENOTEMPTY, fs.Rmdir(Path("/foo"))); 152 EXPECT_EQ(2, root->RefCount()); 153 EXPECT_EQ(2, file->RefCount()); 154 EXPECT_EQ(3, fs.num_nodes()); 155 156 // Unlink the file, we should have the only file ref at this point. 157 EXPECT_EQ(0, fs.Unlink(Path("/foo/bar"))); 158 EXPECT_EQ(2, root->RefCount()); 159 EXPECT_EQ(1, file->RefCount()); 160 EXPECT_EQ(3, fs.num_nodes()); 161 162 // Deref the file, to make it go away 163 file.reset(); 164 EXPECT_EQ(2, fs.num_nodes()); 165 166 // Deref the directory 167 EXPECT_EQ(0, fs.Rmdir(Path("/foo"))); 168 EXPECT_EQ(1, fs.num_nodes()); 169 170 // Verify the directory is gone 171 EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDONLY, &file)); 172 EXPECT_EQ(NULL_NODE, file.get()); 173 } 174 175 TEST(FilesystemTest, OpenMode_TRUNC) { 176 MemFsForTesting fs; 177 ScopedNode file; 178 ScopedNode root; 179 ScopedNode result_node; 180 HandleAttr attrs; 181 int result_bytes; 182 183 // Open a file and write something to it. 184 const char* buf = "hello"; 185 ASSERT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &file)); 186 ASSERT_EQ(0, file->Write(attrs, buf, strlen(buf), &result_bytes)); 187 ASSERT_EQ(strlen(buf), result_bytes); 188 189 // Open it again with TRUNC and make sure it is empty 190 char read_buf[10]; 191 ASSERT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_TRUNC, &file)); 192 ASSERT_EQ(0, file->Read(attrs, read_buf, sizeof(read_buf), &result_bytes)); 193 ASSERT_EQ(0, result_bytes); 194 } 195 196 TEST(FilesystemTest, MemFsRemove) { 197 MemFsForTesting fs; 198 ScopedNode file; 199 ScopedNode result_node; 200 201 ASSERT_EQ(0, fs.Mkdir(Path("/dir"), O_RDWR)); 202 ASSERT_EQ(0, fs.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file)); 203 EXPECT_NE(NULL_NODE, file.get()); 204 EXPECT_EQ(3, fs.num_nodes()); 205 file.reset(); 206 207 EXPECT_EQ(0, fs.Remove(Path("/dir"))); 208 EXPECT_EQ(2, fs.num_nodes()); 209 EXPECT_EQ(0, fs.Remove(Path("/file"))); 210 EXPECT_EQ(1, fs.num_nodes()); 211 212 ASSERT_EQ(ENOENT, fs.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node)); 213 ASSERT_EQ(NULL_NODE, result_node.get()); 214 ASSERT_EQ(ENOENT, fs.Open(Path("/file"), O_RDONLY, &result_node)); 215 ASSERT_EQ(NULL_NODE, result_node.get()); 216 } 217 218 TEST(FilesystemTest, MemFsRename) { 219 MemFsForTesting fs; 220 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR)); 221 ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR)); 222 ASSERT_EQ(3, fs.num_nodes()); 223 224 ScopedNode file; 225 ASSERT_EQ(0, fs.Open(Path("/dir1/file"), O_RDWR | O_CREAT | O_EXCL, &file)); 226 ASSERT_TRUE(fs.Exists("/dir1/file")); 227 ASSERT_EQ(4, fs.num_nodes()); 228 229 // Move from one directory to another should ok 230 ASSERT_EQ(0, fs.Rename(Path("/dir1/file"), Path("/dir2/new_file"))); 231 ASSERT_FALSE(fs.Exists("/dir1/file")); 232 ASSERT_TRUE(fs.Exists("/dir2/new_file")); 233 ASSERT_EQ(4, fs.num_nodes()); 234 235 // Move within the same directory 236 ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file"), Path("/dir2/new_file2"))); 237 ASSERT_FALSE(fs.Exists("/dir2/new_file")); 238 ASSERT_TRUE(fs.Exists("/dir2/new_file2")); 239 ASSERT_EQ(4, fs.num_nodes()); 240 241 // Move to another directory but without a filename 242 ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file2"), Path("/dir1"))); 243 ASSERT_FALSE(fs.Exists("/dir2/new_file2")); 244 ASSERT_TRUE(fs.Exists("/dir1/new_file2")); 245 ASSERT_EQ(4, fs.num_nodes()); 246 } 247 248 TEST(FilesystemTest, MemFsRenameDir) { 249 MemFsForTesting fs; 250 251 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR)); 252 ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR)); 253 EXPECT_EQ(3, fs.num_nodes()); 254 255 // Renaming one directory to another should work 256 ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2"))); 257 ASSERT_FALSE(fs.Exists("/dir1")); 258 ASSERT_TRUE(fs.Exists("/dir2")); 259 EXPECT_EQ(2, fs.num_nodes()); 260 261 // Reset to initial state 262 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR)); 263 EXPECT_EQ(3, fs.num_nodes()); 264 265 // Renaming a directory to a new name within another 266 ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2/foo"))); 267 ASSERT_TRUE(fs.Exists("/dir2")); 268 ASSERT_TRUE(fs.Exists("/dir2/foo")); 269 EXPECT_EQ(3, fs.num_nodes()); 270 271 // Reset to initial state 272 ASSERT_EQ(0, fs.Rmdir(Path("/dir2/foo"))); 273 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR)); 274 EXPECT_EQ(3, fs.num_nodes()); 275 276 // Renaming one directory to another should fail if the target is non-empty 277 ASSERT_EQ(0, fs.Mkdir(Path("/dir2/dir3"), O_RDWR)); 278 ASSERT_EQ(ENOTEMPTY, fs.Rename(Path("/dir1"), Path("/dir2"))); 279 } 280 281 TEST(FilesystemTest, DevAccess) { 282 // Should not be able to open non-existent file. 283 FakePepperInterface pepper; 284 DevFsForTesting fs(&pepper); 285 ScopedNode invalid_node, valid_node; 286 ASSERT_FALSE(fs.Exists("/foo")); 287 // Creating non-existent file should return EACCES 288 ASSERT_EQ(EACCES, fs.Open(Path("/foo"), O_CREAT | O_RDWR, &invalid_node)); 289 290 // We should be able to open all existing nodes with O_CREAT and O_RDWR. 291 ASSERT_EQ(0, fs.Open(Path("/null"), O_CREAT | O_RDWR, &valid_node)); 292 ASSERT_EQ(0, fs.Open(Path("/zero"), O_CREAT | O_RDWR, &valid_node)); 293 ASSERT_EQ(0, fs.Open(Path("/urandom"), O_CREAT | O_RDWR, &valid_node)); 294 ASSERT_EQ(0, fs.Open(Path("/console0"), O_CREAT | O_RDWR, &valid_node)); 295 ASSERT_EQ(0, fs.Open(Path("/console1"), O_CREAT | O_RDWR, &valid_node)); 296 ASSERT_EQ(0, fs.Open(Path("/console3"), O_CREAT | O_RDWR, &valid_node)); 297 ASSERT_EQ(0, fs.Open(Path("/tty"), O_CREAT | O_RDWR, &valid_node)); 298 ASSERT_EQ(0, fs.Open(Path("/stdin"), O_CREAT | O_RDWR, &valid_node)); 299 ASSERT_EQ(0, fs.Open(Path("/stdout"), O_CREAT | O_RDWR, &valid_node)); 300 ASSERT_EQ(0, fs.Open(Path("/stderr"), O_CREAT | O_RDWR, &valid_node)); 301 } 302 303 TEST(FilesystemTest, DevNull) { 304 FakePepperInterface pepper; 305 DevFsForTesting fs(&pepper); 306 ScopedNode dev_null; 307 int result_bytes = 0; 308 struct stat buf; 309 310 ASSERT_EQ(0, fs.Open(Path("/null"), O_RDWR, &dev_null)); 311 ASSERT_NE(NULL_NODE, dev_null.get()); 312 ASSERT_EQ(0, dev_null->GetStat(&buf)); 313 ASSERT_EQ(S_IRUSR | S_IWUSR, buf.st_mode & S_IRWXU); 314 315 // Writing to /dev/null should write everything. 316 const char msg[] = "Dummy test message."; 317 HandleAttr attrs; 318 EXPECT_EQ(0, dev_null->Write(attrs, &msg[0], strlen(msg), &result_bytes)); 319 EXPECT_EQ(strlen(msg), result_bytes); 320 321 // Reading from /dev/null should read nothing. 322 const int kBufferLength = 100; 323 char buffer[kBufferLength]; 324 EXPECT_EQ(0, dev_null->Read(attrs, &buffer[0], kBufferLength, &result_bytes)); 325 EXPECT_EQ(0, result_bytes); 326 } 327 328 TEST(FilesystemTest, DevZero) { 329 FakePepperInterface pepper; 330 DevFsForTesting fs(&pepper); 331 ScopedNode dev_zero; 332 int result_bytes = 0; 333 struct stat buf; 334 335 ASSERT_EQ(0, fs.Open(Path("/zero"), O_RDWR, &dev_zero)); 336 ASSERT_NE(NULL_NODE, dev_zero.get()); 337 ASSERT_EQ(0, dev_zero->GetStat(&buf)); 338 ASSERT_EQ(S_IRUSR | S_IWUSR, buf.st_mode & S_IRWXU); 339 340 // Writing to /dev/zero should write everything. 341 HandleAttr attrs; 342 const char msg[] = "Dummy test message."; 343 EXPECT_EQ(0, dev_zero->Write(attrs, &msg[0], strlen(msg), &result_bytes)); 344 EXPECT_EQ(strlen(msg), result_bytes); 345 346 // Reading from /dev/zero should read all zeroes. 347 const int kBufferLength = 100; 348 char buffer[kBufferLength]; 349 // First fill with all 1s. 350 memset(&buffer[0], 0x1, kBufferLength); 351 EXPECT_EQ(0, dev_zero->Read(attrs, &buffer[0], kBufferLength, &result_bytes)); 352 EXPECT_EQ(kBufferLength, result_bytes); 353 354 char zero_buffer[kBufferLength]; 355 memset(&zero_buffer[0], 0, kBufferLength); 356 EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength)); 357 } 358 359 // Disabled due to intermittent failures on linux: http://crbug.com/257257 360 TEST(FilesystemTest, DISABLED_DevUrandom) { 361 FakePepperInterface pepper; 362 DevFsForTesting fs(&pepper); 363 ScopedNode dev_urandom; 364 int result_bytes = 0; 365 struct stat buf; 366 367 ASSERT_EQ(0, fs.Open(Path("/urandom"), O_RDWR, &dev_urandom)); 368 ASSERT_NE(NULL_NODE, dev_urandom.get()); 369 ASSERT_EQ(0, dev_urandom->GetStat(&buf)); 370 ASSERT_EQ(S_IRUSR | S_IWUSR, buf.st_mode & S_IRWXU); 371 372 // Writing to /dev/urandom should write everything. 373 const char msg[] = "Dummy test message."; 374 HandleAttr attrs; 375 EXPECT_EQ(0, dev_urandom->Write(attrs, &msg[0], strlen(msg), &result_bytes)); 376 EXPECT_EQ(strlen(msg), result_bytes); 377 378 // Reading from /dev/urandom should read random bytes. 379 const int kSampleBatches = 1000; 380 const int kSampleBatchSize = 1000; 381 const int kTotalSamples = kSampleBatches * kSampleBatchSize; 382 383 int byte_count[256] = {0}; 384 385 unsigned char buffer[kSampleBatchSize]; 386 for (int batch = 0; batch < kSampleBatches; ++batch) { 387 int bytes_read = 0; 388 EXPECT_EQ( 389 0, dev_urandom->Read(attrs, &buffer[0], kSampleBatchSize, &bytes_read)); 390 EXPECT_EQ(kSampleBatchSize, bytes_read); 391 392 for (int i = 0; i < bytes_read; ++i) { 393 byte_count[buffer[i]]++; 394 } 395 } 396 397 double expected_count = kTotalSamples / 256.; 398 double chi_squared = 0; 399 for (int i = 0; i < 256; ++i) { 400 double difference = byte_count[i] - expected_count; 401 chi_squared += difference * difference / expected_count; 402 } 403 404 // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom. 405 EXPECT_LE(chi_squared, 293.24); 406 } 407