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 bool Exists(const char* filename
) {
33 if (Open(Path(filename
), O_RDONLY
, &node
))
37 return node
->GetStat(&buf
) == 0;
40 int num_nodes() { return (int)inode_pool_
.size(); }
45 TEST(FilesystemTest
, Sanity
) {
50 ScopedNode result_node
;
52 off_t result_size
= 0;
57 // A memory filesystem starts with one directory node: the root.
58 EXPECT_EQ(1, fs
.num_nodes());
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());
66 EXPECT_EQ(0, fs
.Open(Path("/foo"), O_RDWR
| O_CREAT
, &file
));
67 ASSERT_NE(NULL_NODE
, file
.get());
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
);
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
);
81 // Open the root directory, should not create a new file
82 EXPECT_EQ(0, fs
.Open(Path("/"), O_RDONLY
, &root
));
83 EXPECT_EQ(2, fs
.num_nodes());
84 ASSERT_NE(NULL_NODE
, root
.get());
85 struct dirent dirs
[4];
87 EXPECT_EQ(0, root
->GetDents(0, dirs
, sizeof(dirs
), &len
));
88 // 3 == "foo", ".", ".."
89 EXPECT_EQ(3 * sizeof(struct dirent
), len
);
91 // Fail to re-create the same file
93 fs
.Open(Path("/foo"), O_RDWR
| O_CREAT
| O_EXCL
, &result_node
));
94 EXPECT_EQ(NULL_NODE
, result_node
.get());
95 EXPECT_EQ(2, fs
.num_nodes());
97 // Fail to create a directory with the same name
98 EXPECT_EQ(EEXIST
, fs
.Mkdir(Path("/foo"), O_RDWR
));
99 EXPECT_EQ(2, fs
.num_nodes());
103 // Attempt to READ/WRITE
104 EXPECT_EQ(0, file
->GetSize(&result_size
));
105 EXPECT_EQ(0, result_size
);
106 EXPECT_EQ(0, file
->Write(attrs
, buf1
, sizeof(buf1
), &result_bytes
));
107 EXPECT_EQ(sizeof(buf1
), result_bytes
);
108 EXPECT_EQ(0, file
->GetSize(&result_size
));
109 EXPECT_EQ(sizeof(buf1
), result_size
);
110 EXPECT_EQ(0, file
->Read(attrs
, buf1
, sizeof(buf1
), &result_bytes
));
111 EXPECT_EQ(sizeof(buf1
), result_bytes
);
112 EXPECT_EQ(2, fs
.num_nodes());
113 EXPECT_EQ(2, file
->RefCount());
115 // Attempt to open the same file, create another ref to it, but does not
116 // create a new file.
117 EXPECT_EQ(0, fs
.Open(Path("/foo"), O_RDWR
| O_CREAT
, &result_node
));
118 EXPECT_EQ(3, file
->RefCount());
119 EXPECT_EQ(2, fs
.num_nodes());
120 EXPECT_EQ(file
.get(), result_node
.get());
121 EXPECT_EQ(0, file
->GetSize(&result_size
));
122 EXPECT_EQ(sizeof(buf1
), result_size
);
124 // Remove our references so that only the Filesystem holds it
127 EXPECT_EQ(2, fs
.num_nodes());
129 // This should have deleted the object
130 EXPECT_EQ(0, fs
.Unlink(Path("/foo")));
131 EXPECT_EQ(1, fs
.num_nodes());
133 // We should fail to find it
134 EXPECT_EQ(ENOENT
, fs
.Unlink(Path("/foo")));
135 EXPECT_EQ(1, fs
.num_nodes());
137 // Recreate foo as a directory
138 EXPECT_EQ(0, fs
.Mkdir(Path("/foo"), O_RDWR
));
139 EXPECT_EQ(2, fs
.num_nodes());
141 // Create a file (exclusively)
142 EXPECT_EQ(0, fs
.Open(Path("/foo/bar"), O_RDWR
| O_CREAT
| O_EXCL
, &file
));
143 ASSERT_NE(NULL_NODE
, file
.get());
144 EXPECT_EQ(2, file
->RefCount());
145 EXPECT_EQ(3, fs
.num_nodes());
147 // Attempt to delete the directory and fail
148 EXPECT_EQ(ENOTEMPTY
, fs
.Rmdir(Path("/foo")));
149 EXPECT_EQ(2, root
->RefCount());
150 EXPECT_EQ(2, file
->RefCount());
151 EXPECT_EQ(3, fs
.num_nodes());
153 // Unlink the file, we should have the only file ref at this point.
154 EXPECT_EQ(0, fs
.Unlink(Path("/foo/bar")));
155 EXPECT_EQ(2, root
->RefCount());
156 EXPECT_EQ(1, file
->RefCount());
157 EXPECT_EQ(3, fs
.num_nodes());
159 // Deref the file, to make it go away
161 EXPECT_EQ(2, fs
.num_nodes());
163 // Deref the directory
164 EXPECT_EQ(0, fs
.Rmdir(Path("/foo")));
165 EXPECT_EQ(1, fs
.num_nodes());
167 // Verify the directory is gone
168 EXPECT_EQ(ENOENT
, fs
.Open(Path("/foo"), O_RDONLY
, &file
));
169 EXPECT_EQ(NULL_NODE
, file
.get());
172 TEST(FilesystemTest
, OpenMode_TRUNC
) {
176 ScopedNode result_node
;
180 // Open a file and write something to it.
181 const char* buf
= "hello";
182 ASSERT_EQ(0, fs
.Open(Path("/foo"), O_RDWR
| O_CREAT
, &file
));
183 ASSERT_EQ(0, file
->Write(attrs
, buf
, strlen(buf
), &result_bytes
));
184 ASSERT_EQ(strlen(buf
), result_bytes
);
186 // Open it again with TRUNC and make sure it is empty
188 ASSERT_EQ(0, fs
.Open(Path("/foo"), O_RDWR
| O_TRUNC
, &file
));
189 ASSERT_EQ(0, file
->Read(attrs
, read_buf
, sizeof(read_buf
), &result_bytes
));
190 ASSERT_EQ(0, result_bytes
);
193 TEST(FilesystemTest
, MemFsRemove
) {
196 ScopedNode result_node
;
198 ASSERT_EQ(0, fs
.Mkdir(Path("/dir"), O_RDWR
));
199 ASSERT_EQ(0, fs
.Open(Path("/file"), O_RDWR
| O_CREAT
| O_EXCL
, &file
));
200 EXPECT_NE(NULL_NODE
, file
.get());
201 EXPECT_EQ(3, fs
.num_nodes());
204 EXPECT_EQ(0, fs
.Remove(Path("/dir")));
205 EXPECT_EQ(2, fs
.num_nodes());
206 EXPECT_EQ(0, fs
.Remove(Path("/file")));
207 EXPECT_EQ(1, fs
.num_nodes());
209 ASSERT_EQ(ENOENT
, fs
.Open(Path("/dir/foo"), O_CREAT
| O_RDWR
, &result_node
));
210 ASSERT_EQ(NULL_NODE
, result_node
.get());
211 ASSERT_EQ(ENOENT
, fs
.Open(Path("/file"), O_RDONLY
, &result_node
));
212 ASSERT_EQ(NULL_NODE
, result_node
.get());
215 TEST(FilesystemTest
, MemFsRename
) {
217 ASSERT_EQ(0, fs
.Mkdir(Path("/dir1"), O_RDWR
));
218 ASSERT_EQ(0, fs
.Mkdir(Path("/dir2"), O_RDWR
));
219 ASSERT_EQ(3, fs
.num_nodes());
222 ASSERT_EQ(0, fs
.Open(Path("/dir1/file"), O_RDWR
| O_CREAT
| O_EXCL
, &file
));
223 ASSERT_TRUE(fs
.Exists("/dir1/file"));
224 ASSERT_EQ(4, fs
.num_nodes());
226 // Move from one directory to another should ok
227 ASSERT_EQ(0, fs
.Rename(Path("/dir1/file"), Path("/dir2/new_file")));
228 ASSERT_FALSE(fs
.Exists("/dir1/file"));
229 ASSERT_TRUE(fs
.Exists("/dir2/new_file"));
230 ASSERT_EQ(4, fs
.num_nodes());
232 // Move within the same directory
233 ASSERT_EQ(0, fs
.Rename(Path("/dir2/new_file"), Path("/dir2/new_file2")));
234 ASSERT_FALSE(fs
.Exists("/dir2/new_file"));
235 ASSERT_TRUE(fs
.Exists("/dir2/new_file2"));
236 ASSERT_EQ(4, fs
.num_nodes());
238 // Move to another directory but without a filename
239 ASSERT_EQ(0, fs
.Rename(Path("/dir2/new_file2"), Path("/dir1")));
240 ASSERT_FALSE(fs
.Exists("/dir2/new_file2"));
241 ASSERT_TRUE(fs
.Exists("/dir1/new_file2"));
242 ASSERT_EQ(4, fs
.num_nodes());
245 TEST(FilesystemTest
, MemFsRenameDir
) {
248 ASSERT_EQ(0, fs
.Mkdir(Path("/dir1"), O_RDWR
));
249 ASSERT_EQ(0, fs
.Mkdir(Path("/dir2"), O_RDWR
));
250 EXPECT_EQ(3, fs
.num_nodes());
252 // Renaming one directory to another should work
253 ASSERT_EQ(0, fs
.Rename(Path("/dir1"), Path("/dir2")));
254 ASSERT_FALSE(fs
.Exists("/dir1"));
255 ASSERT_TRUE(fs
.Exists("/dir2"));
256 EXPECT_EQ(2, fs
.num_nodes());
258 // Reset to initial state
259 ASSERT_EQ(0, fs
.Mkdir(Path("/dir1"), O_RDWR
));
260 EXPECT_EQ(3, fs
.num_nodes());
262 // Renaming a directory to a new name within another
263 ASSERT_EQ(0, fs
.Rename(Path("/dir1"), Path("/dir2/foo")));
264 ASSERT_TRUE(fs
.Exists("/dir2"));
265 ASSERT_TRUE(fs
.Exists("/dir2/foo"));
266 EXPECT_EQ(3, fs
.num_nodes());
268 // Reset to initial state
269 ASSERT_EQ(0, fs
.Rmdir(Path("/dir2/foo")));
270 ASSERT_EQ(0, fs
.Mkdir(Path("/dir1"), O_RDWR
));
271 EXPECT_EQ(3, fs
.num_nodes());
273 // Renaming one directory to another should fail if the target is non-empty
274 ASSERT_EQ(0, fs
.Mkdir(Path("/dir2/dir3"), O_RDWR
));
275 ASSERT_EQ(ENOTEMPTY
, fs
.Rename(Path("/dir1"), Path("/dir2")));
278 TEST(FilesystemTest
, DevAccess
) {
279 // Should not be able to open non-existent file.
280 FakePepperInterface pepper
;
281 DevFsForTesting
fs(&pepper
);
282 ScopedNode invalid_node
, valid_node
;
283 ASSERT_FALSE(fs
.Exists("/foo"));
284 // Creating non-existent file should return EACCES
285 ASSERT_EQ(EACCES
, fs
.Open(Path("/foo"), O_CREAT
| O_RDWR
, &invalid_node
));
287 // We should be able to open all existing nodes with O_CREAT and O_RDWR.
288 ASSERT_EQ(0, fs
.Open(Path("/null"), O_CREAT
| O_RDWR
, &valid_node
));
289 ASSERT_EQ(0, fs
.Open(Path("/zero"), O_CREAT
| O_RDWR
, &valid_node
));
290 ASSERT_EQ(0, fs
.Open(Path("/urandom"), O_CREAT
| O_RDWR
, &valid_node
));
291 ASSERT_EQ(0, fs
.Open(Path("/console0"), O_CREAT
| O_RDWR
, &valid_node
));
292 ASSERT_EQ(0, fs
.Open(Path("/console1"), O_CREAT
| O_RDWR
, &valid_node
));
293 ASSERT_EQ(0, fs
.Open(Path("/console3"), O_CREAT
| O_RDWR
, &valid_node
));
294 ASSERT_EQ(0, fs
.Open(Path("/tty"), O_CREAT
| O_RDWR
, &valid_node
));
295 ASSERT_EQ(0, fs
.Open(Path("/stdin"), O_CREAT
| O_RDWR
, &valid_node
));
296 ASSERT_EQ(0, fs
.Open(Path("/stdout"), O_CREAT
| O_RDWR
, &valid_node
));
297 ASSERT_EQ(0, fs
.Open(Path("/stderr"), O_CREAT
| O_RDWR
, &valid_node
));
300 TEST(FilesystemTest
, DevNull
) {
301 FakePepperInterface pepper
;
302 DevFsForTesting
fs(&pepper
);
304 int result_bytes
= 0;
307 ASSERT_EQ(0, fs
.Open(Path("/null"), O_RDWR
, &dev_null
));
308 ASSERT_NE(NULL_NODE
, dev_null
.get());
309 ASSERT_EQ(0, dev_null
->GetStat(&buf
));
310 ASSERT_EQ(S_IRUSR
| S_IWUSR
, buf
.st_mode
& S_IRWXU
);
312 // Writing to /dev/null should write everything.
313 const char msg
[] = "Dummy test message.";
315 EXPECT_EQ(0, dev_null
->Write(attrs
, &msg
[0], strlen(msg
), &result_bytes
));
316 EXPECT_EQ(strlen(msg
), result_bytes
);
318 // Reading from /dev/null should read nothing.
319 const int kBufferLength
= 100;
320 char buffer
[kBufferLength
];
321 EXPECT_EQ(0, dev_null
->Read(attrs
, &buffer
[0], kBufferLength
, &result_bytes
));
322 EXPECT_EQ(0, result_bytes
);
325 TEST(FilesystemTest
, DevZero
) {
326 FakePepperInterface pepper
;
327 DevFsForTesting
fs(&pepper
);
329 int result_bytes
= 0;
332 ASSERT_EQ(0, fs
.Open(Path("/zero"), O_RDWR
, &dev_zero
));
333 ASSERT_NE(NULL_NODE
, dev_zero
.get());
334 ASSERT_EQ(0, dev_zero
->GetStat(&buf
));
335 ASSERT_EQ(S_IRUSR
| S_IWUSR
, buf
.st_mode
& S_IRWXU
);
337 // Writing to /dev/zero should write everything.
339 const char msg
[] = "Dummy test message.";
340 EXPECT_EQ(0, dev_zero
->Write(attrs
, &msg
[0], strlen(msg
), &result_bytes
));
341 EXPECT_EQ(strlen(msg
), result_bytes
);
343 // Reading from /dev/zero should read all zeroes.
344 const int kBufferLength
= 100;
345 char buffer
[kBufferLength
];
346 // First fill with all 1s.
347 memset(&buffer
[0], 0x1, kBufferLength
);
348 EXPECT_EQ(0, dev_zero
->Read(attrs
, &buffer
[0], kBufferLength
, &result_bytes
));
349 EXPECT_EQ(kBufferLength
, result_bytes
);
351 char zero_buffer
[kBufferLength
];
352 memset(&zero_buffer
[0], 0, kBufferLength
);
353 EXPECT_EQ(0, memcmp(&buffer
[0], &zero_buffer
[0], kBufferLength
));
356 // Disabled due to intermittent failures on linux: http://crbug.com/257257
357 TEST(FilesystemTest
, DISABLED_DevUrandom
) {
358 FakePepperInterface pepper
;
359 DevFsForTesting
fs(&pepper
);
360 ScopedNode dev_urandom
;
361 int result_bytes
= 0;
364 ASSERT_EQ(0, fs
.Open(Path("/urandom"), O_RDWR
, &dev_urandom
));
365 ASSERT_NE(NULL_NODE
, dev_urandom
.get());
366 ASSERT_EQ(0, dev_urandom
->GetStat(&buf
));
367 ASSERT_EQ(S_IRUSR
| S_IWUSR
, buf
.st_mode
& S_IRWXU
);
369 // Writing to /dev/urandom should write everything.
370 const char msg
[] = "Dummy test message.";
372 EXPECT_EQ(0, dev_urandom
->Write(attrs
, &msg
[0], strlen(msg
), &result_bytes
));
373 EXPECT_EQ(strlen(msg
), result_bytes
);
375 // Reading from /dev/urandom should read random bytes.
376 const int kSampleBatches
= 1000;
377 const int kSampleBatchSize
= 1000;
378 const int kTotalSamples
= kSampleBatches
* kSampleBatchSize
;
380 int byte_count
[256] = {0};
382 unsigned char buffer
[kSampleBatchSize
];
383 for (int batch
= 0; batch
< kSampleBatches
; ++batch
) {
386 0, dev_urandom
->Read(attrs
, &buffer
[0], kSampleBatchSize
, &bytes_read
));
387 EXPECT_EQ(kSampleBatchSize
, bytes_read
);
389 for (int i
= 0; i
< bytes_read
; ++i
) {
390 byte_count
[buffer
[i
]]++;
394 double expected_count
= kTotalSamples
/ 256.;
395 double chi_squared
= 0;
396 for (int i
= 0; i
< 256; ++i
) {
397 double difference
= byte_count
[i
] - expected_count
;
398 chi_squared
+= difference
* difference
/ expected_count
;
401 // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
402 EXPECT_LE(chi_squared
, 293.24);