filesystem_test.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
20using namespace nacl_io;
21
22namespace {
23
24class 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
45TEST(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
175TEST(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
196TEST(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
218TEST(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
248TEST(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
281TEST(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
303TEST(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
328TEST(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
360TEST(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