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_IRALL | S_IWALL | S_IXALL) {
69 ~DirNodeForTesting() { s_alloc_num--; }
72 using DirNode::AddChild;
73 using DirNode::RemoveChild;
74 using DirNode::FindChild;
79 TEST(MemFsNodeTest, File) {
80 MemFsNodeForTesting file;
81 ScopedNode result_node;
82 off_t result_size = 0;
85 EXPECT_EQ(0, file.Init(0));
88 EXPECT_EQ(0, file.GetLinks());
89 EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode());
90 EXPECT_EQ(S_IFREG, file.GetType());
91 EXPECT_FALSE(file.IsaDir());
92 EXPECT_TRUE(file.IsaFile());
93 EXPECT_EQ(ENOTTY, file.Isatty());
94 EXPECT_EQ(0, file.RefCount());
99 for (size_t a = 0; a < sizeof(buf1); a++)
101 memset(buf2, 0, sizeof(buf2));
104 EXPECT_EQ(0, file.GetSize(&result_size));
105 EXPECT_EQ(0, result_size);
106 EXPECT_EQ(0, file.Read(attr, buf2, sizeof(buf2), &result_bytes));
107 EXPECT_EQ(0, result_bytes);
108 EXPECT_EQ(0, file.GetSize(&result_size));
109 EXPECT_EQ(0, result_size);
110 EXPECT_EQ(0, file.Write(attr, buf1, sizeof(buf1), &result_bytes));
111 EXPECT_EQ(sizeof(buf1), result_bytes);
112 EXPECT_EQ(0, file.GetSize(&result_size));
113 EXPECT_EQ(sizeof(buf1), result_size);
114 EXPECT_EQ(0, file.Read(attr, buf2, sizeof(buf2), &result_bytes));
115 EXPECT_EQ(sizeof(buf1), result_bytes);
116 EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
119 EXPECT_EQ(0, file.GetStat(&s));
120 EXPECT_LT(0, s.st_ino); // 0 is an invalid inode number.
121 EXPECT_EQ(sizeof(buf1), s.st_size);
123 // Directory operations should fail
125 EXPECT_EQ(ENOTDIR, file.GetDents(0, &d, sizeof(d), &result_bytes));
126 EXPECT_EQ(ENOTDIR, file.AddChild("", result_node));
127 EXPECT_EQ(ENOTDIR, file.RemoveChild(""));
128 EXPECT_EQ(ENOTDIR, file.FindChild("", &result_node));
129 EXPECT_EQ(NULL_NODE, result_node.get());
132 TEST(MemFsNodeTest, Fchmod) {
133 MemFsNodeForTesting file;
135 ASSERT_EQ(0, file.Init(0));
136 EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode());
139 ASSERT_EQ(0, file.GetStat(&s));
140 EXPECT_TRUE(S_ISREG(s.st_mode));
141 EXPECT_EQ(S_IRALL | S_IWALL, s.st_mode & S_MODEBITS);
143 // Change to read-only.
144 EXPECT_EQ(0, file.Fchmod(S_IRALL));
146 EXPECT_EQ(S_IRALL, file.GetMode());
148 ASSERT_EQ(0, file.GetStat(&s));
149 EXPECT_EQ(S_IFREG | S_IRALL, s.st_mode);
152 TEST(MemFsNodeTest, FTruncate) {
153 MemFsNodeForTesting file;
154 off_t result_size = 0;
155 int result_bytes = 0;
161 for (size_t a = 0; a < sizeof(data); a++)
163 memset(buffer, 0, sizeof(buffer));
164 memset(zero, 0, sizeof(zero));
167 // Write the data to the file.
168 ASSERT_EQ(0, file.Write(attr, data, sizeof(data), &result_bytes));
169 ASSERT_EQ(sizeof(data), result_bytes);
171 // Double the size of the file.
172 EXPECT_EQ(0, file.FTruncate(sizeof(data) * 2));
173 EXPECT_EQ(0, file.GetSize(&result_size));
174 EXPECT_EQ(sizeof(data) * 2, result_size);
176 // Read the first half of the file, it shouldn't have changed.
177 EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes));
178 EXPECT_EQ(sizeof(buffer), result_bytes);
179 EXPECT_EQ(0, memcmp(buffer, data, sizeof(buffer)));
181 // Read the second half of the file, it should be all zeroes.
182 attr.offs = sizeof(data);
183 EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes));
184 EXPECT_EQ(sizeof(buffer), result_bytes);
185 EXPECT_EQ(0, memcmp(buffer, zero, sizeof(buffer)));
187 // Decrease the size of the file.
188 EXPECT_EQ(0, file.FTruncate(100));
189 EXPECT_EQ(0, file.GetSize(&result_size));
190 EXPECT_EQ(100, result_size);
192 // Data should still be there.
194 EXPECT_EQ(0, file.Read(attr, buffer, sizeof(buffer), &result_bytes));
195 EXPECT_EQ(100, result_bytes);
196 EXPECT_EQ(0, memcmp(buffer, data, 100));
199 TEST(MemFsNodeTest, Fcntl_GETFL) {
200 MemFsNodeForTesting* node = new MemFsNodeForTesting();
201 ScopedFilesystem fs(new MemFsForTesting());
202 ScopedNode file(node);
203 KernelHandle handle(fs, file);
204 ASSERT_EQ(0, handle.Init(O_CREAT | O_APPEND));
206 // Test invalid fcntl command.
207 ASSERT_EQ(ENOSYS, handle.Fcntl(-1, NULL));
210 ASSERT_EQ(0, node->Init(0));
212 ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags));
213 ASSERT_EQ(O_CREAT | O_APPEND, flags);
216 // Test adding of O_NONBLOCK
217 flags = O_NONBLOCK | O_APPEND;
218 ASSERT_EQ(0, handle.Fcntl(F_SETFL, NULL, flags));
219 ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags));
220 ASSERT_EQ(O_CREAT | O_APPEND | O_NONBLOCK, flags);
222 // Clearing of O_APPEND should generate EPERM;
224 ASSERT_EQ(EPERM, handle.Fcntl(F_SETFL, NULL, flags));
227 TEST(MemFsNodeTest, Directory) {
229 DirNodeForTesting root;
230 ScopedNode result_node;
231 off_t result_size = 0;
232 int result_bytes = 0;
237 EXPECT_EQ(0, root.GetLinks());
238 // Directories are always executable.
239 EXPECT_EQ(S_IRALL | S_IWALL | S_IXALL, root.GetMode());
240 EXPECT_EQ(S_IFDIR, root.GetType());
241 EXPECT_TRUE(root.IsaDir());
242 EXPECT_FALSE(root.IsaFile());
243 EXPECT_EQ(ENOTTY, root.Isatty());
244 EXPECT_EQ(0, root.RefCount());
246 // IO operations should fail
249 EXPECT_EQ(0, root.GetSize(&result_size));
250 EXPECT_EQ(0, result_size);
251 EXPECT_EQ(EISDIR, root.Read(attr, buf1, sizeof(buf1), &result_bytes));
252 EXPECT_EQ(EISDIR, root.Write(attr, buf1, sizeof(buf1), &result_bytes));
255 EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL));
256 EXPECT_EQ(S_IRALL | S_IWALL, root.GetMode());
258 EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL | S_IXALL));
260 // Test directory operations
261 MemFsNodeForTesting* raw_file = new MemFsNodeForTesting;
262 EXPECT_EQ(0, raw_file->Init(0));
263 ScopedNode file(raw_file);
265 EXPECT_EQ(0, root.RefCount());
266 EXPECT_EQ(1, file->RefCount());
267 EXPECT_EQ(0, root.AddChild("F1", file));
268 EXPECT_EQ(1, file->GetLinks());
269 EXPECT_EQ(2, file->RefCount());
271 // Test that the directory is there
272 const size_t kMaxDirents = 4;
273 struct dirent d[kMaxDirents];
274 EXPECT_EQ(0, root.GetDents(0, &d[0], sizeof(d), &result_bytes));
277 size_t num_dirents = result_bytes / sizeof(dirent);
278 EXPECT_EQ(3, num_dirents);
279 EXPECT_EQ(sizeof(dirent) * num_dirents, result_bytes);
281 std::multiset<std::string> dirnames;
282 for (int i = 0; i < num_dirents; ++i) {
283 EXPECT_LT(0, d[i].d_ino); // 0 is an invalid inode number.
284 EXPECT_EQ(sizeof(dirent), d[i].d_off);
285 EXPECT_EQ(sizeof(dirent), d[i].d_reclen);
286 dirnames.insert(d[i].d_name);
289 EXPECT_EQ(1, dirnames.count("F1"));
290 EXPECT_EQ(1, dirnames.count("."));
291 EXPECT_EQ(1, dirnames.count(".."));
294 // There should only be 3 entries. Reading past that will return 0 bytes read.
295 EXPECT_EQ(0, root.GetDents(sizeof(d), &d[0], sizeof(d), &result_bytes));
296 EXPECT_EQ(0, result_bytes);
298 EXPECT_EQ(0, root.AddChild("F2", file));
299 EXPECT_EQ(2, file->GetLinks());
300 EXPECT_EQ(3, file->RefCount());
301 EXPECT_EQ(EEXIST, root.AddChild("F1", file));
302 EXPECT_EQ(2, file->GetLinks());
303 EXPECT_EQ(3, file->RefCount());
305 EXPECT_EQ(2, s_alloc_num);
306 EXPECT_EQ(0, root.FindChild("F1", &result_node));
307 EXPECT_NE(NULL_NODE, result_node.get());
308 EXPECT_EQ(0, root.FindChild("F2", &result_node));
309 EXPECT_NE(NULL_NODE, result_node.get());
310 EXPECT_EQ(ENOENT, root.FindChild("F3", &result_node));
311 EXPECT_EQ(NULL_NODE, result_node.get());
313 EXPECT_EQ(2, s_alloc_num);
314 EXPECT_EQ(0, root.RemoveChild("F1"));
315 EXPECT_EQ(1, file->GetLinks());
316 EXPECT_EQ(2, file->RefCount());
317 EXPECT_EQ(0, root.RemoveChild("F2"));
318 EXPECT_EQ(0, file->GetLinks());
319 EXPECT_EQ(1, file->RefCount());
320 EXPECT_EQ(2, s_alloc_num);
323 EXPECT_EQ(1, s_alloc_num);
326 TEST(MemFsNodeTest, OpenMode) {
327 MemFsNodeForTesting* node = new MemFsNodeForTesting();
328 ScopedFilesystem fs(new MemFsForTesting());
329 ScopedNode file(node);
331 const char write_buf[] = "hello world";
335 // Write some data to the file
337 KernelHandle handle(fs, file);
338 ASSERT_EQ(0, handle.Init(O_CREAT | O_WRONLY));
339 ASSERT_EQ(0, handle.Write(write_buf, strlen(write_buf), &byte_count));
340 ASSERT_EQ(byte_count, strlen(write_buf));
343 // Reading from the O_WRONLY handle should be impossible
346 KernelHandle handle(fs, file);
347 ASSERT_EQ(0, handle.Init(O_WRONLY));
348 ASSERT_EQ(EACCES, handle.Read(read_buf, 10, &byte_count));
349 ASSERT_EQ(0, handle.Write(write_buf, strlen(write_buf), &byte_count));
350 ASSERT_EQ(byte_count, strlen(write_buf));
353 // Writing to a O_RDONLY handle should fail
356 KernelHandle handle(fs, file);
357 ASSERT_EQ(0, handle.Init(O_RDONLY));
358 ASSERT_EQ(EACCES, handle.Write(write_buf, strlen(write_buf), &byte_count));
359 ASSERT_EQ(0, handle.Read(read_buf, sizeof(read_buf), &byte_count));
360 ASSERT_EQ(byte_count, sizeof(read_buf));