1// Copyright (c) 2012 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 "nacl_io/error.h"
9#include "nacl_io/ioctl.h"
10#include "nacl_io/kernel_proxy.h"
11#include "nacl_io/mount_dev.h"
12#include "nacl_io/mount_node.h"
13#include "nacl_io/mount_node_dir.h"
14#include "nacl_io/mount_node_mem.h"
15#include "nacl_io/osdirent.h"
16
17#include "gtest/gtest.h"
18
19#define NULL_NODE ((MountNode*) NULL)
20
21using namespace nacl_io;
22
23static int s_AllocNum = 0;
24
25class MockMemory : public MountNodeMem {
26 public:
27  MockMemory() : MountNodeMem(NULL) { s_AllocNum++; }
28
29  ~MockMemory() { s_AllocNum--; }
30
31  Error Init(int mode) { return MountNodeMem::Init(mode); }
32  Error AddChild(const std::string& name, const ScopedMountNode& node) {
33    return MountNodeMem::AddChild(name, node);
34  }
35  Error RemoveChild(const std::string& name) {
36    return MountNodeMem::RemoveChild(name);
37  }
38  Error FindChild(const std::string& name, ScopedMountNode* out_node) {
39    return MountNodeMem::FindChild(name, out_node);
40  }
41  void Link() { MountNodeMem::Link(); }
42  void Unlink() { MountNodeMem::Unlink(); }
43
44 protected:
45  using MountNodeMem::Init;
46};
47
48class MockDir : public MountNodeDir {
49 public:
50  MockDir() : MountNodeDir(NULL) { s_AllocNum++; }
51
52  ~MockDir() { s_AllocNum--; }
53
54  Error Init(int mode) { return MountNodeDir::Init(mode); }
55  Error AddChild(const std::string& name, const ScopedMountNode& node) {
56    return MountNodeDir::AddChild(name, node);
57  }
58  Error RemoveChild(const std::string& name) {
59    return MountNodeDir::RemoveChild(name);
60  }
61  Error FindChild(const std::string& name, ScopedMountNode* out_node) {
62    return MountNodeDir::FindChild(name, out_node);
63  }
64  void Link() { MountNodeDir::Link(); }
65  void Unlink() { MountNodeDir::Unlink(); }
66
67 protected:
68  using MountNodeDir::Init;
69};
70
71TEST(MountNodeTest, File) {
72  MockMemory* file = new MockMemory;
73  ScopedMountNode result_node;
74  size_t result_size = 0;
75  int result_bytes = 0;
76
77  EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
78
79  // Test properties
80  EXPECT_EQ(0, file->GetLinks());
81  EXPECT_EQ(S_IREAD | S_IWRITE, file->GetMode());
82  EXPECT_EQ(S_IFREG, file->GetType());
83  EXPECT_FALSE(file->IsaDir());
84  EXPECT_TRUE(file->IsaFile());
85  EXPECT_FALSE(file->IsaTTY());
86  EXPECT_EQ(0, file->RefCount());
87
88  // Test IO
89  char buf1[1024];
90  char buf2[1024 * 2];
91  for (size_t a = 0; a < sizeof(buf1); a++)
92    buf1[a] = a;
93  memset(buf2, 0, sizeof(buf2));
94
95  EXPECT_EQ(0, file->GetSize(&result_size));
96  EXPECT_EQ(0, result_size);
97  EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
98  EXPECT_EQ(0, result_bytes);
99  EXPECT_EQ(0, file->GetSize(&result_size));
100  EXPECT_EQ(0, result_size);
101  EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
102  EXPECT_EQ(sizeof(buf1), result_bytes);
103  EXPECT_EQ(0, file->GetSize(&result_size));
104  EXPECT_EQ(sizeof(buf1), result_size);
105  EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
106  EXPECT_EQ(sizeof(buf1), result_bytes);
107  EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
108
109  struct stat s;
110  EXPECT_EQ(0, file->GetStat(&s));
111  EXPECT_LT(0, s.st_ino);  // 0 is an invalid inode number.
112  EXPECT_EQ(sizeof(buf1), s.st_size);
113
114  // Directory operations should fail
115  struct dirent d;
116  EXPECT_EQ(ENOTDIR, file->GetDents(0, &d, sizeof(d), &result_bytes));
117  EXPECT_EQ(ENOTDIR, file->AddChild("", result_node));
118  EXPECT_EQ(ENOTDIR, file->RemoveChild(""));
119  EXPECT_EQ(ENOTDIR, file->FindChild("", &result_node));
120  EXPECT_EQ(NULL_NODE, result_node.get());
121
122  delete file;
123}
124
125TEST(MountNodeTest, Directory) {
126  MockDir* root = new MockDir();
127  ScopedMountNode result_node;
128  size_t result_size = 0;
129  int result_bytes = 0;
130
131  root->Init(S_IREAD | S_IWRITE);
132
133  // Test properties
134  EXPECT_EQ(0, root->GetLinks());
135  EXPECT_EQ(S_IREAD | S_IWRITE, root->GetMode());
136  EXPECT_EQ(S_IFDIR, root->GetType());
137  EXPECT_TRUE(root->IsaDir());
138  EXPECT_FALSE(root->IsaFile());
139  EXPECT_FALSE(root->IsaTTY());
140  EXPECT_EQ(0, root->RefCount());
141
142  // IO operations should fail
143  char buf1[1024];
144  EXPECT_EQ(0, root->GetSize(&result_size));
145  EXPECT_EQ(0, result_size);
146  EXPECT_EQ(EISDIR, root->Read(0, buf1, sizeof(buf1), &result_bytes));
147  EXPECT_EQ(EISDIR, root->Write(0, buf1, sizeof(buf1), &result_bytes));
148
149  // Test directory operations
150  MockMemory* raw_file = new MockMemory;
151  EXPECT_EQ(0, raw_file->Init(S_IREAD | S_IWRITE));
152  ScopedMountNode file(raw_file);
153
154  EXPECT_EQ(0, root->RefCount());
155  EXPECT_EQ(1, file->RefCount());
156  EXPECT_EQ(0, root->AddChild("F1", file));
157  EXPECT_EQ(1, file->GetLinks());
158  EXPECT_EQ(2, file->RefCount());
159
160  // Test that the directory is there
161  struct dirent d;
162  EXPECT_EQ(0, root->GetDents(0, &d, sizeof(d), &result_bytes));
163  EXPECT_EQ(sizeof(d), result_bytes);
164  EXPECT_LT(0, d.d_ino);  // 0 is an invalid inode number.
165  EXPECT_EQ(sizeof(d), d.d_off);
166  EXPECT_EQ(sizeof(d), d.d_reclen);
167  EXPECT_EQ(0, strcmp("F1", d.d_name));
168  EXPECT_EQ(0, root->GetDents(sizeof(d), &d, sizeof(d), &result_bytes));
169  EXPECT_EQ(0, result_bytes);
170
171  EXPECT_EQ(0, root->AddChild("F2", file));
172  EXPECT_EQ(2, file->GetLinks());
173  EXPECT_EQ(3, file->RefCount());
174  EXPECT_EQ(EEXIST, root->AddChild("F1", file));
175  EXPECT_EQ(2, file->GetLinks());
176  EXPECT_EQ(3, file->RefCount());
177
178  EXPECT_EQ(2, s_AllocNum);
179  EXPECT_EQ(0, root->FindChild("F1", &result_node));
180  EXPECT_NE(NULL_NODE, result_node.get());
181  EXPECT_EQ(0, root->FindChild("F2", &result_node));
182  EXPECT_NE(NULL_NODE, result_node.get());
183  EXPECT_EQ(ENOENT, root->FindChild("F3", &result_node));
184  EXPECT_EQ(NULL_NODE, result_node.get());
185
186  EXPECT_EQ(2, s_AllocNum);
187  EXPECT_EQ(0, root->RemoveChild("F1"));
188  EXPECT_EQ(1, file->GetLinks());
189  EXPECT_EQ(2, file->RefCount());
190  EXPECT_EQ(0, root->RemoveChild("F2"));
191  EXPECT_EQ(0, file->GetLinks());
192  EXPECT_EQ(1, file->RefCount());
193  EXPECT_EQ(2, s_AllocNum);
194
195  file.reset();
196  EXPECT_EQ(1, s_AllocNum);
197}
198