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 
      8 #include <set>
      9 #include <string>
     10 
     11 #include "gtest/gtest.h"
     12 
     13 #include "nacl_io/devfs/dev_fs.h"
     14 #include "nacl_io/dir_node.h"
     15 #include "nacl_io/error.h"
     16 #include "nacl_io/ioctl.h"
     17 #include "nacl_io/kernel_handle.h"
     18 #include "nacl_io/kernel_proxy.h"
     19 #include "nacl_io/memfs/mem_fs.h"
     20 #include "nacl_io/memfs/mem_fs_node.h"
     21 #include "nacl_io/node.h"
     22 #include "nacl_io/osdirent.h"
     23 
     24 #define NULL_NODE ((Node*)NULL)
     25 
     26 using namespace nacl_io;
     27 
     28 static int s_alloc_num = 0;
     29 
     30 namespace {
     31 
     32 class MemFsForTesting : public MemFs {
     33  public:
     34   MemFsForTesting() {
     35     FsInitArgs args(1);
     36     EXPECT_EQ(0, Init(args));
     37   }
     38 
     39   bool Exists(const char* filename) {
     40     ScopedNode node;
     41     if (Open(Path(filename), O_RDONLY, &node))
     42       return false;
     43 
     44     struct stat buf;
     45     return node->GetStat(&buf) == 0;
     46   }
     47 
     48   int num_nodes() { return inode_pool_.size(); }
     49 };
     50 
     51 class MemFsNodeForTesting : public MemFsNode {
     52  public:
     53   MemFsNodeForTesting() : MemFsNode(NULL) { s_alloc_num++; }
     54 
     55   ~MemFsNodeForTesting() { s_alloc_num--; }
     56 
     57   using MemFsNode::Init;
     58   using MemFsNode::AddChild;
     59   using MemFsNode::RemoveChild;
     60   using MemFsNode::FindChild;
     61 };
     62 
     63 class DirNodeForTesting : public DirNode {
     64  public:
     65   DirNodeForTesting() : DirNode(NULL) { s_alloc_num++; }
     66 
     67   ~DirNodeForTesting() { s_alloc_num--; }
     68 
     69   using DirNode::Init;
     70   using DirNode::AddChild;
     71   using DirNode::RemoveChild;
     72   using DirNode::FindChild;
     73 };
     74 
     75 }  // namespace
     76 
     77 TEST(MemFsNodeTest, File) {
     78   MemFsNodeForTesting file;
     79   ScopedNode result_node;
     80   off_t result_size = 0;
     81   int result_bytes = 0;
     82 
     83   EXPECT_EQ(0, file.Init(0));
     84 
     85   // Test properties
     86   EXPECT_EQ(0, file.GetLinks());
     87   EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode());
     88   EXPECT_EQ(S_IFREG, file.GetType());
     89   EXPECT_FALSE(file.IsaDir());
     90   EXPECT_TRUE(file.IsaFile());
     91   EXPECT_EQ(ENOTTY, file.Isatty());
     92   EXPECT_EQ(0, file.RefCount());
     93 
     94   // Test IO
     95   char buf1[1024];
     96   char buf2[1024 * 2];
     97   for (size_t a = 0; a < sizeof(buf1); a++)
     98     buf1[a] = a;
     99   memset(buf2, 0, sizeof(buf2));
    100   HandleAttr attr;
    101 
    102   EXPECT_EQ(0, file.GetSize(&result_size));
    103   EXPECT_EQ(0, result_size);
    104   EXPECT_EQ(0, file.Read(attr, buf2, sizeof(buf2), &result_bytes));
    105   EXPECT_EQ(0, result_bytes);
    106   EXPECT_EQ(0, file.GetSize(&result_size));
    107   EXPECT_EQ(0, result_size);
    108   EXPECT_EQ(0, file.Write(attr, buf1, sizeof(buf1), &result_bytes));
    109   EXPECT_EQ(sizeof(buf1), result_bytes);
    110   EXPECT_EQ(0, file.GetSize(&result_size));
    111   EXPECT_EQ(sizeof(buf1), result_size);
    112   EXPECT_EQ(0, file.Read(attr, buf2, sizeof(buf2), &result_bytes));
    113   EXPECT_EQ(sizeof(buf1), result_bytes);
    114   EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
    115 
    116   struct stat s;
    117   EXPECT_EQ(0, file.GetStat(&s));
    118   EXPECT_LT(0, s.st_ino);  // 0 is an invalid inode number.
    119   EXPECT_EQ(sizeof(buf1), s.st_size);
    120 
    121   // Directory operations should fail
    122   struct dirent d;
    123   EXPECT_EQ(ENOTDIR, file.GetDents(0, &d, sizeof(d), &result_bytes));
    124   EXPECT_EQ(ENOTDIR, file.AddChild("", result_node));
    125   EXPECT_EQ(ENOTDIR, file.RemoveChild(""));
    126   EXPECT_EQ(ENOTDIR, file.FindChild("", &result_node));
    127   EXPECT_EQ(NULL_NODE, result_node.get());
    128 }
    129 
    130 TEST(MemFsNodeTest, Fchmod) {
    131   MemFsNodeForTesting file;
    132 
    133   ASSERT_EQ(0, file.Init(0));
    134   EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode());
    135 
    136   struct stat s;
    137   ASSERT_EQ(0, file.GetStat(&s));
    138   EXPECT_EQ(S_IFREG | S_IRALL | S_IWALL, s.st_mode);
    139 
    140   // Change to read-only.
    141   EXPECT_EQ(0, file.Fchmod(S_IRALL));
    142 
    143   EXPECT_EQ(S_IRALL, file.GetMode());
    144 
    145   ASSERT_EQ(0, file.GetStat(&s));
    146   EXPECT_EQ(S_IFREG | S_IRALL, s.st_mode);
    147 }
    148 
    149 TEST(MemFsNodeTest, FTruncate) {
    150   MemFsNodeForTesting file;
    151   off_t result_size = 0;
    152   int result_bytes = 0;
    153 
    154   char data[1024];
    155   char buffer[1024];
    156   char zero[1024];
    157 
    158   for (size_t a = 0; a < sizeof(data); a++)
    159     data[a] = a;
    160   memset(buffer, 0, sizeof(buffer));
    161   memset(zero, 0, sizeof(zero));
    162   HandleAttr attr;
    163 
    164   // Write the data to the file.
    165   ASSERT_EQ(0, file.Write(attr, data, sizeof(data), &result_bytes));
    166   ASSERT_EQ(sizeof(data), result_bytes);
    167 
    168   // Double the size of the file.
    169   EXPECT_EQ(0, file.FTruncate(sizeof(data) * 2));
    170   EXPECT_EQ(0, file.GetSize(&result_size));
    171   EXPECT_EQ(sizeof(data) * 2, result_size);
    172 
    173   // Read the first half of the file, it shouldn't have changed.
    174   EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes));
    175   EXPECT_EQ(sizeof(buffer), result_bytes);
    176   EXPECT_EQ(0, memcmp(buffer, data, sizeof(buffer)));
    177 
    178   // Read the second half of the file, it should be all zeroes.
    179   attr.offs = sizeof(data);
    180   EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes));
    181   EXPECT_EQ(sizeof(buffer), result_bytes);
    182   EXPECT_EQ(0, memcmp(buffer, zero, sizeof(buffer)));
    183 
    184   // Decrease the size of the file.
    185   EXPECT_EQ(0, file.FTruncate(100));
    186   EXPECT_EQ(0, file.GetSize(&result_size));
    187   EXPECT_EQ(100, result_size);
    188 
    189   // Data should still be there.
    190   attr.offs = 0;
    191   EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes));
    192   EXPECT_EQ(100, result_bytes);
    193   EXPECT_EQ(0, memcmp(buffer, data, 100));
    194 }
    195 
    196 TEST(MemFsNodeTest, Fcntl_GETFL) {
    197   MemFsNodeForTesting* node = new MemFsNodeForTesting();
    198   ScopedFilesystem fs(new MemFsForTesting());
    199   ScopedNode file(node);
    200   KernelHandle handle(fs, file);
    201   ASSERT_EQ(0, handle.Init(O_CREAT | O_APPEND));
    202 
    203   // Test invalid fcntl command.
    204   ASSERT_EQ(ENOSYS, handle.Fcntl(-1, NULL));
    205 
    206   // Test F_GETFL
    207   ASSERT_EQ(0, node->Init(0));
    208   int flags = 0;
    209   ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags));
    210   ASSERT_EQ(O_CREAT | O_APPEND, flags);
    211 
    212   // Test F_SETFL
    213   // Test adding of O_NONBLOCK
    214   flags = O_NONBLOCK | O_APPEND;
    215   ASSERT_EQ(0, handle.Fcntl(F_SETFL, NULL, flags));
    216   ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags));
    217   ASSERT_EQ(O_CREAT | O_APPEND | O_NONBLOCK, flags);
    218 
    219   // Clearing of O_APPEND should generate EPERM;
    220   flags = O_NONBLOCK;
    221   ASSERT_EQ(EPERM, handle.Fcntl(F_SETFL, NULL, flags));
    222 }
    223 
    224 TEST(MemFsNodeTest, Directory) {
    225   s_alloc_num = 0;
    226   DirNodeForTesting root;
    227   ScopedNode result_node;
    228   off_t result_size = 0;
    229   int result_bytes = 0;
    230 
    231   root.Init(0);
    232 
    233   // Test properties
    234   EXPECT_EQ(0, root.GetLinks());
    235   // Directories are always executable.
    236   EXPECT_EQ(S_IRALL | S_IWALL | S_IXALL, root.GetMode());
    237   EXPECT_EQ(S_IFDIR, root.GetType());
    238   EXPECT_TRUE(root.IsaDir());
    239   EXPECT_FALSE(root.IsaFile());
    240   EXPECT_EQ(ENOTTY, root.Isatty());
    241   EXPECT_EQ(0, root.RefCount());
    242 
    243   // IO operations should fail
    244   char buf1[1024];
    245   HandleAttr attr;
    246   EXPECT_EQ(0, root.GetSize(&result_size));
    247   EXPECT_EQ(0, result_size);
    248   EXPECT_EQ(EISDIR, root.Read(attr, buf1, sizeof(buf1), &result_bytes));
    249   EXPECT_EQ(EISDIR, root.Write(attr, buf1, sizeof(buf1), &result_bytes));
    250 
    251   // Chmod test
    252   EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL));
    253   EXPECT_EQ(S_IRALL | S_IWALL, root.GetMode());
    254   // Change it back.
    255   EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL | S_IXALL));
    256 
    257   // Test directory operations
    258   MemFsNodeForTesting* raw_file = new MemFsNodeForTesting;
    259   EXPECT_EQ(0, raw_file->Init(0));
    260   ScopedNode file(raw_file);
    261 
    262   EXPECT_EQ(0, root.RefCount());
    263   EXPECT_EQ(1, file->RefCount());
    264   EXPECT_EQ(0, root.AddChild("F1", file));
    265   EXPECT_EQ(1, file->GetLinks());
    266   EXPECT_EQ(2, file->RefCount());
    267 
    268   // Test that the directory is there
    269   const size_t kMaxDirents = 4;
    270   struct dirent d[kMaxDirents];
    271   EXPECT_EQ(0, root.GetDents(0, &d[0], sizeof(d), &result_bytes));
    272 
    273   {
    274     size_t num_dirents = result_bytes / sizeof(dirent);
    275     EXPECT_EQ(3, num_dirents);
    276     EXPECT_EQ(sizeof(dirent) * num_dirents, result_bytes);
    277 
    278     std::multiset<std::string> dirnames;
    279     for (int i = 0; i < num_dirents; ++i) {
    280       EXPECT_LT(0, d[i].d_ino);  // 0 is an invalid inode number.
    281       EXPECT_EQ(sizeof(dirent), d[i].d_off);
    282       EXPECT_EQ(sizeof(dirent), d[i].d_reclen);
    283       dirnames.insert(d[i].d_name);
    284     }
    285 
    286     EXPECT_EQ(1, dirnames.count("F1"));
    287     EXPECT_EQ(1, dirnames.count("."));
    288     EXPECT_EQ(1, dirnames.count(".."));
    289   }
    290 
    291   // There should only be 3 entries. Reading past that will return 0 bytes read.
    292   EXPECT_EQ(0, root.GetDents(sizeof(d), &d[0], sizeof(d), &result_bytes));
    293   EXPECT_EQ(0, result_bytes);
    294 
    295   EXPECT_EQ(0, root.AddChild("F2", file));
    296   EXPECT_EQ(2, file->GetLinks());
    297   EXPECT_EQ(3, file->RefCount());
    298   EXPECT_EQ(EEXIST, root.AddChild("F1", file));
    299   EXPECT_EQ(2, file->GetLinks());
    300   EXPECT_EQ(3, file->RefCount());
    301 
    302   EXPECT_EQ(2, s_alloc_num);
    303   EXPECT_EQ(0, root.FindChild("F1", &result_node));
    304   EXPECT_NE(NULL_NODE, result_node.get());
    305   EXPECT_EQ(0, root.FindChild("F2", &result_node));
    306   EXPECT_NE(NULL_NODE, result_node.get());
    307   EXPECT_EQ(ENOENT, root.FindChild("F3", &result_node));
    308   EXPECT_EQ(NULL_NODE, result_node.get());
    309 
    310   EXPECT_EQ(2, s_alloc_num);
    311   EXPECT_EQ(0, root.RemoveChild("F1"));
    312   EXPECT_EQ(1, file->GetLinks());
    313   EXPECT_EQ(2, file->RefCount());
    314   EXPECT_EQ(0, root.RemoveChild("F2"));
    315   EXPECT_EQ(0, file->GetLinks());
    316   EXPECT_EQ(1, file->RefCount());
    317   EXPECT_EQ(2, s_alloc_num);
    318 
    319   file.reset();
    320   EXPECT_EQ(1, s_alloc_num);
    321 }
    322 
    323 TEST(MemFsNodeTest, OpenMode) {
    324   MemFsNodeForTesting* node = new MemFsNodeForTesting();
    325   ScopedFilesystem fs(new MemFsForTesting());
    326   ScopedNode file(node);
    327 
    328   const char write_buf[] = "hello world";
    329   char read_buf[10];
    330   int byte_count = 0;
    331 
    332   // Write some data to the file
    333   {
    334     KernelHandle handle(fs, file);
    335     ASSERT_EQ(0, handle.Init(O_CREAT | O_WRONLY));
    336     ASSERT_EQ(0, handle.Write(write_buf, strlen(write_buf), &byte_count));
    337     ASSERT_EQ(byte_count, strlen(write_buf));
    338   }
    339 
    340   // Reading from the O_WRONLY handle should be impossible
    341   {
    342     byte_count = 0;
    343     KernelHandle handle(fs, file);
    344     ASSERT_EQ(0, handle.Init(O_WRONLY));
    345     ASSERT_EQ(EACCES, handle.Read(read_buf, 10, &byte_count));
    346     ASSERT_EQ(0, handle.Write(write_buf, strlen(write_buf), &byte_count));
    347     ASSERT_EQ(byte_count, strlen(write_buf));
    348   }
    349 
    350   // Writing to a O_RDONLY handle should fail
    351   {
    352     byte_count = 0;
    353     KernelHandle handle(fs, file);
    354     ASSERT_EQ(0, handle.Init(O_RDONLY));
    355     ASSERT_EQ(EACCES, handle.Write(write_buf, strlen(write_buf), &byte_count));
    356     ASSERT_EQ(0, handle.Read(read_buf, sizeof(read_buf), &byte_count));
    357     ASSERT_EQ(byte_count, sizeof(read_buf));
    358   }
    359 }
    360