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.
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"
20 using namespace nacl_io;
24 class MemFsForTesting : public MemFs {
28 EXPECT_EQ(0, Init(args));
31 int num_nodes() { return (int)inode_pool_.size(); }
36 TEST(FilesystemTest, Sanity) {
41 ScopedNode result_node;
43 off_t result_size = 0;
47 // A memory filesystem starts with one directory node: the root.
48 EXPECT_EQ(1, fs.num_nodes());
50 // Fail to open non existent file
51 EXPECT_EQ(ENOENT, fs.Access(Path("/foo"), R_OK | W_OK));
52 EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDWR, &result_node));
53 EXPECT_EQ(NULL, result_node.get());
54 EXPECT_EQ(1, fs.num_nodes());
57 EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &file));
58 ASSERT_NE(NULL_NODE, file.get());
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, fs.num_nodes());
63 EXPECT_EQ(2, file->RefCount());
64 EXPECT_EQ(0, fs.Access(Path("/foo"), R_OK | W_OK));
65 EXPECT_EQ(EACCES, fs.Access(Path("/foo"), X_OK));
67 // All access should be allowed on the root directory.
68 EXPECT_EQ(0, fs.Access(Path("/"), R_OK | W_OK | X_OK));
69 // Open the root directory for write should fail.
70 EXPECT_EQ(EISDIR, fs.Open(Path("/"), O_RDWR, &root));
71 EXPECT_EQ(2, fs.num_nodes());
73 // Open the root directory, should not create a new file
74 EXPECT_EQ(0, fs.Open(Path("/"), O_RDONLY, &root));
75 EXPECT_EQ(2, fs.num_nodes());
76 ASSERT_NE(NULL_NODE, root.get());
77 struct dirent dirs[4];
79 EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
80 // 3 == "foo", ".", ".."
81 EXPECT_EQ(3 * sizeof(struct dirent), len);
83 // Fail to re-create the same file
85 fs.Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
86 EXPECT_EQ(NULL_NODE, result_node.get());
87 EXPECT_EQ(2, fs.num_nodes());
89 // Fail to create a directory with the same name
90 EXPECT_EQ(EEXIST, fs.Mkdir(Path("/foo"), O_RDWR));
91 EXPECT_EQ(2, fs.num_nodes());
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, fs.num_nodes());
105 EXPECT_EQ(2, file->RefCount());
107 // Attempt to open the same file, create another ref to it, but does not
108 // create a new file.
109 EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
110 EXPECT_EQ(3, file->RefCount());
111 EXPECT_EQ(2, fs.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);
116 // Remove our references so that only the Filesystem holds it
119 EXPECT_EQ(2, fs.num_nodes());
121 // This should have deleted the object
122 EXPECT_EQ(0, fs.Unlink(Path("/foo")));
123 EXPECT_EQ(1, fs.num_nodes());
125 // We should fail to find it
126 EXPECT_EQ(ENOENT, fs.Unlink(Path("/foo")));
127 EXPECT_EQ(1, fs.num_nodes());
129 // Recreate foo as a directory
130 EXPECT_EQ(0, fs.Mkdir(Path("/foo"), O_RDWR));
131 EXPECT_EQ(2, fs.num_nodes());
133 // Create a file (exclusively)
134 EXPECT_EQ(0, fs.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, fs.num_nodes());
139 // Attempt to delete the directory and fail
140 EXPECT_EQ(ENOTEMPTY, fs.Rmdir(Path("/foo")));
141 EXPECT_EQ(2, root->RefCount());
142 EXPECT_EQ(2, file->RefCount());
143 EXPECT_EQ(3, fs.num_nodes());
145 // Unlink the file, we should have the only file ref at this point.
146 EXPECT_EQ(0, fs.Unlink(Path("/foo/bar")));
147 EXPECT_EQ(2, root->RefCount());
148 EXPECT_EQ(1, file->RefCount());
149 EXPECT_EQ(3, fs.num_nodes());
151 // Deref the file, to make it go away
153 EXPECT_EQ(2, fs.num_nodes());
155 // Deref the directory
156 EXPECT_EQ(0, fs.Rmdir(Path("/foo")));
157 EXPECT_EQ(1, fs.num_nodes());
159 // Verify the directory is gone
160 EXPECT_EQ(ENOENT, fs.Access(Path("/foo"), F_OK));
161 EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDWR, &file));
162 EXPECT_EQ(NULL_NODE, file.get());
165 TEST(FilesystemTest, OpenMode_TRUNC) {
169 ScopedNode result_node;
173 // Open a file and write something to it.
174 const char* buf = "hello";
175 ASSERT_EQ(0, fs.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);
179 // Open it again with TRUNC and make sure it is empty
181 ASSERT_EQ(0, fs.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);
186 TEST(FilesystemTest, MemFsRemove) {
189 ScopedNode result_node;
191 ASSERT_EQ(0, fs.Mkdir(Path("/dir"), O_RDWR));
192 ASSERT_EQ(0, fs.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
193 EXPECT_NE(NULL_NODE, file.get());
194 EXPECT_EQ(3, fs.num_nodes());
197 EXPECT_EQ(0, fs.Remove(Path("/dir")));
198 EXPECT_EQ(2, fs.num_nodes());
199 EXPECT_EQ(0, fs.Remove(Path("/file")));
200 EXPECT_EQ(1, fs.num_nodes());
202 ASSERT_EQ(ENOENT, fs.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
203 ASSERT_EQ(NULL_NODE, result_node.get());
204 ASSERT_EQ(ENOENT, fs.Open(Path("/file"), O_RDONLY, &result_node));
205 ASSERT_EQ(NULL_NODE, result_node.get());
208 TEST(FilesystemTest, MemFsRename) {
210 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
211 ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR));
212 ASSERT_EQ(3, fs.num_nodes());
215 ASSERT_EQ(0, fs.Open(Path("/dir1/file"), O_RDWR | O_CREAT | O_EXCL, &file));
216 ASSERT_EQ(0, fs.Access(Path("/dir1/file"), R_OK));
217 ASSERT_EQ(4, fs.num_nodes());
219 // Move from one directory to another should ok
220 ASSERT_EQ(0, fs.Rename(Path("/dir1/file"), Path("/dir2/new_file")));
221 ASSERT_NE(0, fs.Access(Path("/dir1/file"), R_OK));
222 ASSERT_EQ(0, fs.Access(Path("/dir2/new_file"), R_OK));
223 ASSERT_EQ(4, fs.num_nodes());
225 // Move within the same directory
226 ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file"), Path("/dir2/new_file2")));
227 ASSERT_NE(0, fs.Access(Path("/dir2/new_file"), R_OK));
228 ASSERT_EQ(0, fs.Access(Path("/dir2/new_file2"), R_OK));
229 ASSERT_EQ(4, fs.num_nodes());
231 // Move to another directory but without a filename
232 ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file2"), Path("/dir1")));
233 ASSERT_NE(0, fs.Access(Path("/dir2/new_file2"), R_OK));
234 ASSERT_EQ(0, fs.Access(Path("/dir1/new_file2"), R_OK));
235 ASSERT_EQ(4, fs.num_nodes());
238 TEST(FilesystemTest, MemFsRenameDir) {
241 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
242 ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR));
243 EXPECT_EQ(3, fs.num_nodes());
245 // Renaming one directory to another should work
246 ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2")));
247 ASSERT_NE(0, fs.Access(Path("/dir1"), R_OK));
248 ASSERT_EQ(0, fs.Access(Path("/dir2"), R_OK));
249 EXPECT_EQ(2, fs.num_nodes());
251 // Reset to initial state
252 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
253 EXPECT_EQ(3, fs.num_nodes());
255 // Renaming a directory to a new name within another
256 ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2/foo")));
257 ASSERT_EQ(0, fs.Access(Path("/dir2"), R_OK));
258 ASSERT_EQ(0, fs.Access(Path("/dir2/foo"), R_OK));
259 EXPECT_EQ(3, fs.num_nodes());
261 // Reset to initial state
262 ASSERT_EQ(0, fs.Rmdir(Path("/dir2/foo")));
263 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
264 EXPECT_EQ(3, fs.num_nodes());
266 // Renaming one directory to another should fail if the target is non-empty
267 ASSERT_EQ(0, fs.Mkdir(Path("/dir2/dir3"), O_RDWR));
268 ASSERT_EQ(ENOTEMPTY, fs.Rename(Path("/dir1"), Path("/dir2")));
271 TEST(FilesystemTest, DevAccess) {
272 // Should not be able to open non-existent file.
273 FakePepperInterface pepper;
274 DevFsForTesting fs(&pepper);
275 ScopedNode invalid_node, valid_node;
276 ASSERT_EQ(ENOENT, fs.Access(Path("/foo"), F_OK));
277 // Creating non-existent file should return EACCES
278 ASSERT_EQ(EACCES, fs.Open(Path("/foo"), O_CREAT | O_RDWR, &invalid_node));
280 // We should be able to open all existing nodes with O_CREAT and O_RDWR.
281 ASSERT_EQ(0, fs.Open(Path("/null"), O_CREAT | O_RDWR, &valid_node));
282 ASSERT_EQ(0, fs.Open(Path("/zero"), O_CREAT | O_RDWR, &valid_node));
283 ASSERT_EQ(0, fs.Open(Path("/urandom"), O_CREAT | O_RDWR, &valid_node));
284 ASSERT_EQ(0, fs.Open(Path("/console0"), O_CREAT | O_RDWR, &valid_node));
285 ASSERT_EQ(0, fs.Open(Path("/console1"), O_CREAT | O_RDWR, &valid_node));
286 ASSERT_EQ(0, fs.Open(Path("/console3"), O_CREAT | O_RDWR, &valid_node));
287 ASSERT_EQ(0, fs.Open(Path("/tty"), O_CREAT | O_RDWR, &valid_node));
288 ASSERT_EQ(0, fs.Open(Path("/stdin"), O_CREAT | O_RDWR, &valid_node));
289 ASSERT_EQ(0, fs.Open(Path("/stdout"), O_CREAT | O_RDWR, &valid_node));
290 ASSERT_EQ(0, fs.Open(Path("/stderr"), O_CREAT | O_RDWR, &valid_node));
293 TEST(FilesystemTest, DevNull) {
294 FakePepperInterface pepper;
295 DevFsForTesting fs(&pepper);
297 int result_bytes = 0;
299 ASSERT_EQ(0, fs.Access(Path("/null"), R_OK | W_OK));
300 ASSERT_EQ(EACCES, fs.Access(Path("/null"), X_OK));
301 ASSERT_EQ(0, fs.Open(Path("/null"), O_RDWR, &dev_null));
302 ASSERT_NE(NULL_NODE, dev_null.get());
304 // Writing to /dev/null should write everything.
305 const char msg[] = "Dummy test message.";
307 EXPECT_EQ(0, dev_null->Write(attrs, &msg[0], strlen(msg), &result_bytes));
308 EXPECT_EQ(strlen(msg), result_bytes);
310 // Reading from /dev/null should read nothing.
311 const int kBufferLength = 100;
312 char buffer[kBufferLength];
313 EXPECT_EQ(0, dev_null->Read(attrs, &buffer[0], kBufferLength, &result_bytes));
314 EXPECT_EQ(0, result_bytes);
317 TEST(FilesystemTest, DevZero) {
318 FakePepperInterface pepper;
319 DevFsForTesting fs(&pepper);
321 int result_bytes = 0;
323 ASSERT_EQ(0, fs.Access(Path("/zero"), R_OK | W_OK));
324 ASSERT_EQ(EACCES, fs.Access(Path("/zero"), X_OK));
325 ASSERT_EQ(0, fs.Open(Path("/zero"), O_RDWR, &dev_zero));
326 ASSERT_NE(NULL_NODE, dev_zero.get());
328 // Writing to /dev/zero should write everything.
330 const char msg[] = "Dummy test message.";
331 EXPECT_EQ(0, dev_zero->Write(attrs, &msg[0], strlen(msg), &result_bytes));
332 EXPECT_EQ(strlen(msg), result_bytes);
334 // Reading from /dev/zero should read all zeroes.
335 const int kBufferLength = 100;
336 char buffer[kBufferLength];
337 // First fill with all 1s.
338 memset(&buffer[0], 0x1, kBufferLength);
339 EXPECT_EQ(0, dev_zero->Read(attrs, &buffer[0], kBufferLength, &result_bytes));
340 EXPECT_EQ(kBufferLength, result_bytes);
342 char zero_buffer[kBufferLength];
343 memset(&zero_buffer[0], 0, kBufferLength);
344 EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
347 // Disabled due to intermittent failures on linux: http://crbug.com/257257
348 TEST(FilesystemTest, DISABLED_DevUrandom) {
349 FakePepperInterface pepper;
350 DevFsForTesting fs(&pepper);
351 ScopedNode dev_urandom;
352 int result_bytes = 0;
354 ASSERT_EQ(0, fs.Access(Path("/urandom"), R_OK | W_OK));
355 ASSERT_EQ(EACCES, fs.Access(Path("/urandom"), X_OK));
356 ASSERT_EQ(0, fs.Open(Path("/urandom"), O_RDWR, &dev_urandom));
357 ASSERT_NE(NULL_NODE, dev_urandom.get());
359 // Writing to /dev/urandom should write everything.
360 const char msg[] = "Dummy test message.";
362 EXPECT_EQ(0, dev_urandom->Write(attrs, &msg[0], strlen(msg), &result_bytes));
363 EXPECT_EQ(strlen(msg), result_bytes);
365 // Reading from /dev/urandom should read random bytes.
366 const int kSampleBatches = 1000;
367 const int kSampleBatchSize = 1000;
368 const int kTotalSamples = kSampleBatches * kSampleBatchSize;
370 int byte_count[256] = {0};
372 unsigned char buffer[kSampleBatchSize];
373 for (int batch = 0; batch < kSampleBatches; ++batch) {
376 0, dev_urandom->Read(attrs, &buffer[0], kSampleBatchSize, &bytes_read));
377 EXPECT_EQ(kSampleBatchSize, bytes_read);
379 for (int i = 0; i < bytes_read; ++i) {
380 byte_count[buffer[i]]++;
384 double expected_count = kTotalSamples / 256.;
385 double chi_squared = 0;
386 for (int i = 0; i < 256; ++i) {
387 double difference = byte_count[i] - expected_count;
388 chi_squared += difference * difference / expected_count;
391 // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
392 EXPECT_LE(chi_squared, 293.24);