Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / tests / nacl_io_test / mem_fs_node_test.cc
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
8 #include <set>
9 #include <string>
10
11 #include "gtest/gtest.h"
12
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"
23
24 #define NULL_NODE ((Node*)NULL)
25
26 using namespace nacl_io;
27
28 static int s_alloc_num = 0;
29
30 namespace {
31
32 class MemFsForTesting : public MemFs {
33  public:
34   MemFsForTesting() {
35     FsInitArgs args(1);
36     EXPECT_EQ(0, Init(args));
37   }
38
39   bool Exists(const char* filename) {
40     ScopedNode node;
41     if (Open(Path(filename), O_RDONLY, &node))
42       return false;
43
44     struct stat buf;
45     return node->GetStat(&buf) == 0;
46   }
47
48   int num_nodes() { return inode_pool_.size(); }
49 };
50
51 class MemFsNodeForTesting : public MemFsNode {
52  public:
53   MemFsNodeForTesting() : MemFsNode(NULL) { s_alloc_num++; }
54
55   ~MemFsNodeForTesting() { s_alloc_num--; }
56
57   using MemFsNode::Init;
58   using MemFsNode::AddChild;
59   using MemFsNode::RemoveChild;
60   using MemFsNode::FindChild;
61 };
62
63 class DirNodeForTesting : public DirNode {
64  public:
65   DirNodeForTesting() : DirNode(NULL, S_IRALL | S_IWALL | S_IXALL) {
66     s_alloc_num++;
67   }
68
69   ~DirNodeForTesting() { s_alloc_num--; }
70
71   using DirNode::Init;
72   using DirNode::AddChild;
73   using DirNode::RemoveChild;
74   using DirNode::FindChild;
75 };
76
77 }  // namespace
78
79 TEST(MemFsNodeTest, File) {
80   MemFsNodeForTesting file;
81   ScopedNode result_node;
82   off_t result_size = 0;
83   int result_bytes = 0;
84
85   EXPECT_EQ(0, file.Init(0));
86
87   // Test properties
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());
95
96   // Test IO
97   char buf1[1024];
98   char buf2[1024 * 2];
99   for (size_t a = 0; a < sizeof(buf1); a++)
100     buf1[a] = a;
101   memset(buf2, 0, sizeof(buf2));
102   HandleAttr attr;
103
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)));
117
118   struct stat s;
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);
122
123   // Directory operations should fail
124   struct dirent d;
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());
130 }
131
132 TEST(MemFsNodeTest, Fchmod) {
133   MemFsNodeForTesting file;
134
135   ASSERT_EQ(0, file.Init(0));
136   EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode());
137
138   struct stat s;
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);
142
143   // Change to read-only.
144   EXPECT_EQ(0, file.Fchmod(S_IRALL));
145
146   EXPECT_EQ(S_IRALL, file.GetMode());
147
148   ASSERT_EQ(0, file.GetStat(&s));
149   EXPECT_EQ(S_IFREG | S_IRALL, s.st_mode);
150 }
151
152 TEST(MemFsNodeTest, FTruncate) {
153   MemFsNodeForTesting file;
154   off_t result_size = 0;
155   int result_bytes = 0;
156
157   char data[1024];
158   char buffer[1024];
159   char zero[1024];
160
161   for (size_t a = 0; a < sizeof(data); a++)
162     data[a] = a;
163   memset(buffer, 0, sizeof(buffer));
164   memset(zero, 0, sizeof(zero));
165   HandleAttr attr;
166
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);
170
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);
175
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)));
180
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)));
186
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);
191
192   // Data should still be there.
193   attr.offs = 0;
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));
197 }
198
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));
205
206   // Test invalid fcntl command.
207   ASSERT_EQ(ENOSYS, handle.Fcntl(-1, NULL));
208
209   // Test F_GETFL
210   ASSERT_EQ(0, node->Init(0));
211   int flags = 0;
212   ASSERT_EQ(0, handle.Fcntl(F_GETFL, &flags));
213   ASSERT_EQ(O_CREAT | O_APPEND, flags);
214
215   // Test F_SETFL
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);
221
222   // Clearing of O_APPEND should generate EPERM;
223   flags = O_NONBLOCK;
224   ASSERT_EQ(EPERM, handle.Fcntl(F_SETFL, NULL, flags));
225 }
226
227 TEST(MemFsNodeTest, Directory) {
228   s_alloc_num = 0;
229   DirNodeForTesting root;
230   ScopedNode result_node;
231   off_t result_size = 0;
232   int result_bytes = 0;
233
234   root.Init(0);
235
236   // Test properties
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());
245
246   // IO operations should fail
247   char buf1[1024];
248   HandleAttr attr;
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));
253
254   // Chmod test
255   EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL));
256   EXPECT_EQ(S_IRALL | S_IWALL, root.GetMode());
257   // Change it back.
258   EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL | S_IXALL));
259
260   // Test directory operations
261   MemFsNodeForTesting* raw_file = new MemFsNodeForTesting;
262   EXPECT_EQ(0, raw_file->Init(0));
263   ScopedNode file(raw_file);
264
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());
270
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));
275
276   {
277     size_t num_dirents = result_bytes / sizeof(dirent);
278     EXPECT_EQ(3, num_dirents);
279     EXPECT_EQ(sizeof(dirent) * num_dirents, result_bytes);
280
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);
287     }
288
289     EXPECT_EQ(1, dirnames.count("F1"));
290     EXPECT_EQ(1, dirnames.count("."));
291     EXPECT_EQ(1, dirnames.count(".."));
292   }
293
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);
297
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());
304
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());
312
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);
321
322   file.reset();
323   EXPECT_EQ(1, s_alloc_num);
324 }
325
326 TEST(MemFsNodeTest, OpenMode) {
327   MemFsNodeForTesting* node = new MemFsNodeForTesting();
328   ScopedFilesystem fs(new MemFsForTesting());
329   ScopedNode file(node);
330
331   const char write_buf[] = "hello world";
332   char read_buf[10];
333   int byte_count = 0;
334
335   // Write some data to the file
336   {
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));
341   }
342
343   // Reading from the O_WRONLY handle should be impossible
344   {
345     byte_count = 0;
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));
351   }
352
353   // Writing to a O_RDONLY handle should fail
354   {
355     byte_count = 0;
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));
361   }
362 }