Home | History | Annotate | Download | only in nacl_io_test
      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