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   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