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