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 "gtest/gtest.h"
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"
24 #define NULL_NODE ((Node*)NULL)
26 using namespace nacl_io;
28 static int s_alloc_num = 0;
32 class MemFsForTesting : public MemFs {
36 EXPECT_EQ(0, Init(args));
39 bool Exists(const char* filename) {
41 if (Open(Path(filename), O_RDONLY, &node))
45 return node->GetStat(&buf) == 0;
48 int num_nodes() { return inode_pool_.size(); }
51 class MemFsNodeForTesting : public MemFsNode {
53 MemFsNodeForTesting() : MemFsNode(NULL) { s_alloc_num++; }
55 ~MemFsNodeForTesting() { s_alloc_num--; }
57 using MemFsNode::Init;
58 using MemFsNode::AddChild;
59 using MemFsNode::RemoveChild;
60 using MemFsNode::FindChild;
63 class DirNodeForTesting : public DirNode {
65 DirNodeForTesting() : DirNode(NULL) { s_alloc_num++; }
67 ~DirNodeForTesting() { s_alloc_num--; }
70 using DirNode::AddChild;
71 using DirNode::RemoveChild;
72 using DirNode::FindChild;
77 TEST(MemFsNodeTest, File) {
78 MemFsNodeForTesting file;
79 ScopedNode result_node;
80 off_t result_size = 0;
83 EXPECT_EQ(0, file.Init(0));
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());
97 for (size_t a = 0; a < sizeof(buf1); a++)
99 memset(buf2, 0, sizeof(buf2));
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)));
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);
121 // Directory operations should fail
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());
130 TEST(MemFsNodeTest, Fchmod) {
131 MemFsNodeForTesting file;
133 ASSERT_EQ(0, file.Init(0));
134 EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode());
137 ASSERT_EQ(0, file.GetStat(&s));
138 EXPECT_EQ(S_IFREG | S_IRALL | S_IWALL, s.st_mode);
140 // Change to read-only.
141 EXPECT_EQ(0, file.Fchmod(S_IRALL));
143 EXPECT_EQ(S_IRALL, file.GetMode());
145 ASSERT_EQ(0, file.GetStat(&s));
146 EXPECT_EQ(S_IFREG | S_IRALL, s.st_mode);
149 TEST(MemFsNodeTest, FTruncate) {
150 MemFsNodeForTesting file;
151 off_t result_size = 0;
152 int result_bytes = 0;
158 for (size_t a = 0; a < sizeof(data); a++)
160 memset(buffer, 0, sizeof(buffer));
161 memset(zero, 0, sizeof(zero));
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);
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);
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)));
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)));
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);
189 // Data should still be there.
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));
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));
203 // Test invalid fcntl command.
204 ASSERT_EQ(ENOSYS, handle.Fcntl(-1, NULL));
207 ASSERT_EQ(0, node->Init(0));
209 ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags));
210 ASSERT_EQ(O_CREAT | O_APPEND, flags);
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);
219 // Clearing of O_APPEND should generate EPERM;
221 ASSERT_EQ(EPERM, handle.Fcntl(F_SETFL, NULL, flags));
224 TEST(MemFsNodeTest, Directory) {
226 DirNodeForTesting root;
227 ScopedNode result_node;
228 off_t result_size = 0;
229 int result_bytes = 0;
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());
243 // IO operations should fail
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));
252 EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL));
253 EXPECT_EQ(S_IRALL | S_IWALL, root.GetMode());
255 EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL | S_IXALL));
257 // Test directory operations
258 MemFsNodeForTesting* raw_file = new MemFsNodeForTesting;
259 EXPECT_EQ(0, raw_file->Init(0));
260 ScopedNode file(raw_file);
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());
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));
274 size_t num_dirents = result_bytes / sizeof(dirent);
275 EXPECT_EQ(3, num_dirents);
276 EXPECT_EQ(sizeof(dirent) * num_dirents, result_bytes);
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);
286 EXPECT_EQ(1, dirnames.count("F1"));
287 EXPECT_EQ(1, dirnames.count("."));
288 EXPECT_EQ(1, dirnames.count(".."));
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);
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());
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());
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);
320 EXPECT_EQ(1, s_alloc_num);
323 TEST(MemFsNodeTest, OpenMode) {
324 MemFsNodeForTesting* node = new MemFsNodeForTesting();
325 ScopedFilesystem fs(new MemFsForTesting());
326 ScopedNode file(node);
328 const char write_buf[] = "hello world";
332 // Write some data to the file
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));
340 // Reading from the O_WRONLY handle should be impossible
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));
350 // Writing to a O_RDONLY handle should fail
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));