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