1 // Copyright (c) 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 "gtest/gtest.h" 12 #include "mount_dev_mock.h" 13 #include "nacl_io/ioctl.h" 14 #include "nacl_io/kernel_handle.h" 15 #include "nacl_io/mount.h" 16 #include "nacl_io/mount_mem.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 MountMemMock : public MountMem { 25 public: 26 MountMemMock() { 27 MountInitArgs 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(MountTest, Sanity) { 37 MountMemMock mnt; 38 39 ScopedMountNode file; 40 ScopedMountNode root; 41 ScopedMountNode result_node; 42 43 size_t result_size = 0; 44 int result_bytes = 0; 45 char buf1[1024]; 46 47 // A memory mount starts with one directory node: the root. 48 EXPECT_EQ(1, mnt.num_nodes()); 49 50 // Fail to open non existent file 51 EXPECT_EQ(ENOENT, mnt.Access(Path("/foo"), R_OK | W_OK)); 52 EXPECT_EQ(ENOENT, mnt.Open(Path("/foo"), O_RDWR, &result_node)); 53 EXPECT_EQ(NULL, result_node.get()); 54 EXPECT_EQ(1, mnt.num_nodes()); 55 56 // Create a file 57 EXPECT_EQ(0, mnt.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, mnt.num_nodes()); 63 EXPECT_EQ(2, file->RefCount()); 64 EXPECT_EQ(0, mnt.Access(Path("/foo"), R_OK | W_OK)); 65 EXPECT_EQ(EACCES, mnt.Access(Path("/foo"), X_OK)); 66 67 // All access should be allowed on the root directory. 68 EXPECT_EQ(0, mnt.Access(Path("/"), R_OK | W_OK | X_OK)); 69 // Open the root directory for write should fail. 70 EXPECT_EQ(EISDIR, mnt.Open(Path("/"), O_RDWR, &root)); 71 EXPECT_EQ(2, mnt.num_nodes()); 72 73 // Open the root directory, should not create a new file 74 EXPECT_EQ(0, mnt.Open(Path("/"), O_RDONLY, &root)); 75 EXPECT_EQ(2, mnt.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 mnt.Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node)); 86 EXPECT_EQ(NULL_NODE, result_node.get()); 87 EXPECT_EQ(2, mnt.num_nodes()); 88 89 // Fail to create a directory with the same name 90 EXPECT_EQ(EEXIST, mnt.Mkdir(Path("/foo"), O_RDWR)); 91 EXPECT_EQ(2, mnt.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, mnt.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, mnt.Open(Path("/foo"), O_RDWR | O_CREAT, &result_node)); 110 EXPECT_EQ(3, file->RefCount()); 111 EXPECT_EQ(2, mnt.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 Mount holds it 117 file.reset(); 118 result_node.reset(); 119 EXPECT_EQ(2, mnt.num_nodes()); 120 121 // This should have deleted the object 122 EXPECT_EQ(0, mnt.Unlink(Path("/foo"))); 123 EXPECT_EQ(1, mnt.num_nodes()); 124 125 // We should fail to find it 126 EXPECT_EQ(ENOENT, mnt.Unlink(Path("/foo"))); 127 EXPECT_EQ(1, mnt.num_nodes()); 128 129 // Recreate foo as a directory 130 EXPECT_EQ(0, mnt.Mkdir(Path("/foo"), O_RDWR)); 131 EXPECT_EQ(2, mnt.num_nodes()); 132 133 // Create a file (exclusively) 134 EXPECT_EQ(0, mnt.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, mnt.num_nodes()); 138 139 // Attempt to delete the directory and fail 140 EXPECT_EQ(ENOTEMPTY, mnt.Rmdir(Path("/foo"))); 141 EXPECT_EQ(2, root->RefCount()); 142 EXPECT_EQ(2, file->RefCount()); 143 EXPECT_EQ(3, mnt.num_nodes()); 144 145 // Unlink the file, we should have the only file ref at this point. 146 EXPECT_EQ(0, mnt.Unlink(Path("/foo/bar"))); 147 EXPECT_EQ(2, root->RefCount()); 148 EXPECT_EQ(1, file->RefCount()); 149 EXPECT_EQ(3, mnt.num_nodes()); 150 151 // Deref the file, to make it go away 152 file.reset(); 153 EXPECT_EQ(2, mnt.num_nodes()); 154 155 // Deref the directory 156 EXPECT_EQ(0, mnt.Rmdir(Path("/foo"))); 157 EXPECT_EQ(1, mnt.num_nodes()); 158 159 // Verify the directory is gone 160 EXPECT_EQ(ENOENT, mnt.Access(Path("/foo"), F_OK)); 161 EXPECT_EQ(ENOENT, mnt.Open(Path("/foo"), O_RDWR, &file)); 162 EXPECT_EQ(NULL_NODE, file.get()); 163 } 164 165 TEST(MountTest, OpenMode_TRUNC) { 166 MountMemMock mnt; 167 ScopedMountNode file; 168 ScopedMountNode root; 169 ScopedMountNode 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, mnt.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, mnt.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(MountTest, MemMountRemove) { 187 MountMemMock mnt; 188 ScopedMountNode file; 189 ScopedMountNode result_node; 190 191 ASSERT_EQ(0, mnt.Mkdir(Path("/dir"), O_RDWR)); 192 ASSERT_EQ(0, mnt.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file)); 193 EXPECT_NE(NULL_NODE, file.get()); 194 EXPECT_EQ(3, mnt.num_nodes()); 195 file.reset(); 196 197 EXPECT_EQ(0, mnt.Remove(Path("/dir"))); 198 EXPECT_EQ(2, mnt.num_nodes()); 199 EXPECT_EQ(0, mnt.Remove(Path("/file"))); 200 EXPECT_EQ(1, mnt.num_nodes()); 201 202 ASSERT_EQ(ENOENT, 203 mnt.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node)); 204 ASSERT_EQ(NULL_NODE, result_node.get()); 205 ASSERT_EQ(ENOENT, mnt.Open(Path("/file"), O_RDONLY, &result_node)); 206 ASSERT_EQ(NULL_NODE, result_node.get()); 207 } 208 209 TEST(MountTest, MemMountRename) { 210 MountMemMock mnt; 211 ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR)); 212 ASSERT_EQ(0, mnt.Mkdir(Path("/dir2"), O_RDWR)); 213 ASSERT_EQ(3, mnt.num_nodes()); 214 215 ScopedMountNode file; 216 ASSERT_EQ(0, mnt.Open(Path("/dir1/file"), O_RDWR | O_CREAT | O_EXCL, &file)); 217 ASSERT_EQ(0, mnt.Access(Path("/dir1/file"), R_OK)); 218 ASSERT_EQ(4, mnt.num_nodes()); 219 220 // Move from one directory to another should ok 221 ASSERT_EQ(0, mnt.Rename(Path("/dir1/file"), Path("/dir2/new_file"))); 222 ASSERT_NE(0, mnt.Access(Path("/dir1/file"), R_OK)); 223 ASSERT_EQ(0, mnt.Access(Path("/dir2/new_file"), R_OK)); 224 ASSERT_EQ(4, mnt.num_nodes()); 225 226 // Move within the same directory 227 ASSERT_EQ(0, mnt.Rename(Path("/dir2/new_file"), Path("/dir2/new_file2"))); 228 ASSERT_NE(0, mnt.Access(Path("/dir2/new_file"), R_OK)); 229 ASSERT_EQ(0, mnt.Access(Path("/dir2/new_file2"), R_OK)); 230 ASSERT_EQ(4, mnt.num_nodes()); 231 232 // Move to another directory but without a filename 233 ASSERT_EQ(0, mnt.Rename(Path("/dir2/new_file2"), Path("/dir1"))); 234 ASSERT_NE(0, mnt.Access(Path("/dir2/new_file2"), R_OK)); 235 ASSERT_EQ(0, mnt.Access(Path("/dir1/new_file2"), R_OK)); 236 ASSERT_EQ(4, mnt.num_nodes()); 237 } 238 239 TEST(MountTest, MemMountRenameDir) { 240 MountMemMock mnt; 241 242 ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR)); 243 ASSERT_EQ(0, mnt.Mkdir(Path("/dir2"), O_RDWR)); 244 EXPECT_EQ(3, mnt.num_nodes()); 245 246 // Renaming one directory to another should work 247 ASSERT_EQ(0, mnt.Rename(Path("/dir1"), Path("/dir2"))); 248 ASSERT_NE(0, mnt.Access(Path("/dir1"), R_OK)); 249 ASSERT_EQ(0, mnt.Access(Path("/dir2"), R_OK)); 250 EXPECT_EQ(2, mnt.num_nodes()); 251 252 // Reset to initial state 253 ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR)); 254 EXPECT_EQ(3, mnt.num_nodes()); 255 256 // Renaming a directory to a new name within another 257 ASSERT_EQ(0, mnt.Rename(Path("/dir1"), Path("/dir2/foo"))); 258 ASSERT_EQ(0, mnt.Access(Path("/dir2"), R_OK)); 259 ASSERT_EQ(0, mnt.Access(Path("/dir2/foo"), R_OK)); 260 EXPECT_EQ(3, mnt.num_nodes()); 261 262 // Reset to initial state 263 ASSERT_EQ(0, mnt.Rmdir(Path("/dir2/foo"))); 264 ASSERT_EQ(0, mnt.Mkdir(Path("/dir1"), O_RDWR)); 265 EXPECT_EQ(3, mnt.num_nodes()); 266 267 // Renaming one directory to another should fail if the target is non-empty 268 ASSERT_EQ(0, mnt.Mkdir(Path("/dir2/dir3"), O_RDWR)); 269 ASSERT_EQ(ENOTEMPTY, mnt.Rename(Path("/dir1"), Path("/dir2"))); 270 } 271 272 TEST(MountTest, DevAccess) { 273 // Should not be able to open non-existent file. 274 MountDevMock mnt; 275 ASSERT_EQ(ENOENT, mnt.Access(Path("/foo"), F_OK)); 276 } 277 278 TEST(MountTest, DevNull) { 279 MountDevMock mnt; 280 ScopedMountNode dev_null; 281 int result_bytes = 0; 282 283 ASSERT_EQ(0, mnt.Access(Path("/null"), R_OK | W_OK)); 284 ASSERT_EQ(EACCES, mnt.Access(Path("/null"), X_OK)); 285 ASSERT_EQ(0, mnt.Open(Path("/null"), O_RDWR, &dev_null)); 286 ASSERT_NE(NULL_NODE, dev_null.get()); 287 288 // Writing to /dev/null should write everything. 289 const char msg[] = "Dummy test message."; 290 HandleAttr attrs; 291 EXPECT_EQ(0, dev_null->Write(attrs, &msg[0], strlen(msg), &result_bytes)); 292 EXPECT_EQ(strlen(msg), result_bytes); 293 294 // Reading from /dev/null should read nothing. 295 const int kBufferLength = 100; 296 char buffer[kBufferLength]; 297 EXPECT_EQ(0, dev_null->Read(attrs, &buffer[0], kBufferLength, &result_bytes)); 298 EXPECT_EQ(0, result_bytes); 299 } 300 301 TEST(MountTest, DevZero) { 302 MountDevMock mnt; 303 ScopedMountNode dev_zero; 304 int result_bytes = 0; 305 306 ASSERT_EQ(0, mnt.Access(Path("/zero"), R_OK | W_OK)); 307 ASSERT_EQ(EACCES, mnt.Access(Path("/zero"), X_OK)); 308 ASSERT_EQ(0, mnt.Open(Path("/zero"), O_RDWR, &dev_zero)); 309 ASSERT_NE(NULL_NODE, dev_zero.get()); 310 311 // Writing to /dev/zero should write everything. 312 HandleAttr attrs; 313 const char msg[] = "Dummy test message."; 314 EXPECT_EQ(0, dev_zero->Write(attrs, &msg[0], strlen(msg), &result_bytes)); 315 EXPECT_EQ(strlen(msg), result_bytes); 316 317 // Reading from /dev/zero should read all zeroes. 318 const int kBufferLength = 100; 319 char buffer[kBufferLength]; 320 // First fill with all 1s. 321 memset(&buffer[0], 0x1, kBufferLength); 322 EXPECT_EQ(0, dev_zero->Read(attrs, &buffer[0], kBufferLength, &result_bytes)); 323 EXPECT_EQ(kBufferLength, result_bytes); 324 325 char zero_buffer[kBufferLength]; 326 memset(&zero_buffer[0], 0, kBufferLength); 327 EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength)); 328 } 329 330 // Disabled due to intermittent failures on linux: http://crbug.com/257257 331 TEST(MountTest, DISABLED_DevUrandom) { 332 MountDevMock mnt; 333 ScopedMountNode dev_urandom; 334 int result_bytes = 0; 335 336 ASSERT_EQ(0, mnt.Access(Path("/urandom"), R_OK | W_OK)); 337 ASSERT_EQ(EACCES, mnt.Access(Path("/urandom"), X_OK)); 338 ASSERT_EQ(0, mnt.Open(Path("/urandom"), O_RDWR, &dev_urandom)); 339 ASSERT_NE(NULL_NODE, dev_urandom.get()); 340 341 // Writing to /dev/urandom should write everything. 342 const char msg[] = "Dummy test message."; 343 HandleAttr attrs; 344 EXPECT_EQ(0, dev_urandom->Write(attrs, &msg[0], strlen(msg), &result_bytes)); 345 EXPECT_EQ(strlen(msg), result_bytes); 346 347 // Reading from /dev/urandom should read random bytes. 348 const int kSampleBatches = 1000; 349 const int kSampleBatchSize = 1000; 350 const int kTotalSamples = kSampleBatches * kSampleBatchSize; 351 352 int byte_count[256] = {0}; 353 354 unsigned char buffer[kSampleBatchSize]; 355 for (int batch = 0; batch < kSampleBatches; ++batch) { 356 int bytes_read = 0; 357 EXPECT_EQ(0, dev_urandom->Read(attrs, &buffer[0], kSampleBatchSize, 358 &bytes_read)); 359 EXPECT_EQ(kSampleBatchSize, bytes_read); 360 361 for (int i = 0; i < bytes_read; ++i) { 362 byte_count[buffer[i]]++; 363 } 364 } 365 366 double expected_count = kTotalSamples / 256.; 367 double chi_squared = 0; 368 for (int i = 0; i < 256; ++i) { 369 double difference = byte_count[i] - expected_count; 370 chi_squared += difference * difference / expected_count; 371 } 372 373 // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom. 374 EXPECT_LE(chi_squared, 293.24); 375 } 376