1 // Copyright 2017 The Fuchsia 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 <fs/pseudo-file.h>
6 
7 #include <fbl/vector.h>
8 #include <initializer_list>
9 #include <unittest/unittest.h>
10 
11 #define EXPECT_FSTR_EQ(expected, actual)                                \
12     EXPECT_BYTES_EQ(reinterpret_cast<const uint8_t*>(expected.c_str()), \
13                     reinterpret_cast<const uint8_t*>(actual.c_str()),   \
14                     expected.size() + 1u, "unequal fbl::String")
15 
16 namespace {
17 
DummyReader(fbl::String * output)18 zx_status_t DummyReader(fbl::String* output) {
19     return ZX_OK;
20 }
21 
DummyWriter(fbl::StringPiece input)22 zx_status_t DummyWriter(fbl::StringPiece input) {
23     return ZX_OK;
24 }
25 
26 class VectorReader {
27 public:
VectorReader(std::initializer_list<fbl::String> strings)28     VectorReader(std::initializer_list<fbl::String> strings)
29         : strings_(strings) {}
30 
GetHandler()31     fs::PseudoFile::ReadHandler GetHandler() {
32         return [this](fbl::String* output) {
33             if (index_ >= strings_.size())
34                 return ZX_ERR_IO;
35             *output = strings_[index_++];
36             return ZX_OK;
37         };
38     }
39 
strings() const40     const fbl::Vector<fbl::String>& strings() const { return strings_; }
41 
42 private:
43     fbl::Vector<fbl::String> strings_;
44     size_t index_ = 0u;
45 };
46 
47 class VectorWriter {
48 public:
VectorWriter(size_t max_strings)49     VectorWriter(size_t max_strings)
50         : max_strings_(max_strings) {}
51 
GetHandler()52     fs::PseudoFile::WriteHandler GetHandler() {
53         return [this](fbl::StringPiece input) {
54             if (strings_.size() >= max_strings_)
55                 return ZX_ERR_IO;
56             strings_.push_back(fbl::String(input));
57             return ZX_OK;
58         };
59     }
60 
strings() const61     const fbl::Vector<fbl::String>& strings() const { return strings_; }
62 
63 private:
64     const size_t max_strings_;
65     fbl::Vector<fbl::String> strings_;
66 };
67 
CheckRead(const fbl::RefPtr<fs::Vnode> & file,zx_status_t status,size_t length,size_t offset,fbl::StringPiece expected)68 bool CheckRead(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status,
69                size_t length, size_t offset, fbl::StringPiece expected) {
70     BEGIN_HELPER;
71 
72     uint8_t buf[length];
73     memset(buf, '!', length);
74     size_t actual = 0u;
75     EXPECT_EQ(status, file->Read(buf, length, offset, &actual));
76     EXPECT_EQ(expected.size(), actual);
77     EXPECT_BYTES_EQ(reinterpret_cast<const uint8_t*>(expected.data()), buf, expected.size(), "");
78 
79     END_HELPER;
80 }
81 
CheckWrite(const fbl::RefPtr<fs::Vnode> & file,zx_status_t status,size_t offset,fbl::StringPiece content,size_t expected_actual)82 bool CheckWrite(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status,
83                 size_t offset, fbl::StringPiece content, size_t expected_actual) {
84     BEGIN_HELPER;
85 
86     size_t actual = 0u;
87     EXPECT_EQ(status, file->Write(content.data(), content.size(), offset, &actual));
88     EXPECT_EQ(expected_actual, actual);
89 
90     END_HELPER;
91 }
92 
CheckAppend(const fbl::RefPtr<fs::Vnode> & file,zx_status_t status,fbl::StringPiece content,size_t expected_end,size_t expected_actual)93 bool CheckAppend(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status,
94                  fbl::StringPiece content, size_t expected_end, size_t expected_actual) {
95     BEGIN_HELPER;
96 
97     size_t end = 0u;
98     size_t actual = 0u;
99     EXPECT_EQ(status, file->Append(content.data(), content.size(), &end, &actual));
100     EXPECT_EQ(expected_end, end);
101     EXPECT_EQ(expected_actual, actual);
102 
103     END_HELPER;
104 }
105 
TestOpenValidationBuffered()106 bool TestOpenValidationBuffered() {
107     BEGIN_TEST;
108 
109     // no read handler, no write handler
110     {
111         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile());
112         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
113         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
114         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
115         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
116     }
117 
118     // read handler, no write handler
119     {
120         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader));
121         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
122         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
123         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
124 
125         fbl::RefPtr<fs::Vnode> redirect;
126         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
127         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
128         EXPECT_NONNULL(redirect);
129     }
130 
131     // no read handler, write handler
132     {
133         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(nullptr, &DummyWriter));
134         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
135         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
136         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
137 
138         fbl::RefPtr<fs::Vnode> redirect;
139         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
140         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
141         EXPECT_NONNULL(redirect);
142     }
143 
144     // read handler, write handler
145     {
146         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader, &DummyWriter));
147         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
148 
149         fbl::RefPtr<fs::Vnode> redirect;
150         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
151         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
152         EXPECT_NONNULL(redirect);
153         redirect.reset();
154         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
155         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
156         EXPECT_NONNULL(redirect);
157         redirect.reset();
158         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
159         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
160         EXPECT_NONNULL(redirect);
161     }
162 
163     END_TEST;
164 }
165 
TestOpenValidationUnbuffered()166 bool TestOpenValidationUnbuffered() {
167     BEGIN_TEST;
168 
169     // no read handler, no write handler
170     {
171         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile());
172         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
173         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
174         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
175         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
176     }
177 
178     // read handler, no write handler
179     {
180         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader));
181         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
182         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
183         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
184         fbl::RefPtr<fs::Vnode> redirect;
185         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
186         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
187         EXPECT_NONNULL(redirect);
188     }
189 
190     // no read handler, write handler
191     {
192         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(nullptr, &DummyWriter));
193         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
194         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
195         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
196         fbl::RefPtr<fs::Vnode> redirect;
197         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
198         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
199         EXPECT_NONNULL(redirect);
200     }
201 
202     // read handler, write handler
203     {
204         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader, &DummyWriter));
205         EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
206         fbl::RefPtr<fs::Vnode> redirect;
207         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
208         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
209         EXPECT_NONNULL(redirect);
210         redirect.reset();
211         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
212         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
213         EXPECT_NONNULL(redirect);
214         redirect.reset();
215         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
216         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
217         EXPECT_NONNULL(redirect);
218     }
219 
220     END_TEST;
221 }
222 
TestGetattrBuffered()223 bool TestGetattrBuffered() {
224     BEGIN_TEST;
225 
226     // no read handler, no write handler
227     {
228         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile());
229         vnattr_t attr;
230         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
231         EXPECT_EQ(V_TYPE_FILE, attr.mode);
232         EXPECT_EQ(1, attr.nlink);
233         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_FLAG_VNODE_REF_ONLY));
234         vnattr_t path_attr;
235         EXPECT_EQ(ZX_OK, file->Getattr(&path_attr));
236         EXPECT_BYTES_EQ((uint8_t*) &attr, (uint8_t*) &path_attr, sizeof(attr), "");
237     }
238 
239     // read handler, no write handler
240     {
241         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader));
242         vnattr_t attr;
243         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
244         EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode);
245         EXPECT_EQ(1, attr.nlink);
246 
247         fbl::RefPtr<fs::Vnode> redirect;
248         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
249         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
250         vnattr_t open_attr;
251         EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
252         EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
253     }
254 
255     // no read handler, write handler
256     {
257         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(nullptr, &DummyWriter));
258         vnattr_t attr;
259         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
260         EXPECT_EQ(V_TYPE_FILE | V_IWUSR, attr.mode);
261         EXPECT_EQ(1, attr.nlink);
262 
263         fbl::RefPtr<fs::Vnode> redirect;
264         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
265         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
266         vnattr_t open_attr;
267         EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
268         EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
269     }
270 
271     // read handler, write handler
272     {
273         auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader, &DummyWriter));
274         vnattr_t attr;
275         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
276         EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode);
277         EXPECT_EQ(1, attr.nlink);
278 
279         fbl::RefPtr<fs::Vnode> redirect;
280         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
281         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
282         vnattr_t open_attr;
283         EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
284         EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
285     }
286 
287     END_TEST;
288 }
289 
TestGetattrUnbuffered()290 bool TestGetattrUnbuffered() {
291     BEGIN_TEST;
292 
293     // no read handler, no write handler
294     {
295         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile());
296         vnattr_t attr;
297         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
298         EXPECT_EQ(V_TYPE_FILE, attr.mode);
299         EXPECT_EQ(1, attr.nlink);
300 
301         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_FLAG_VNODE_REF_ONLY));
302         vnattr_t path_attr;
303         EXPECT_EQ(ZX_OK, file->Getattr(&path_attr));
304         EXPECT_BYTES_EQ((uint8_t*) &attr, (uint8_t*) &path_attr, sizeof(attr), "");
305     }
306 
307     // read handler, no write handler
308     {
309         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader));
310         vnattr_t attr;
311         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
312         EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode);
313         EXPECT_EQ(1, attr.nlink);
314 
315         fbl::RefPtr<fs::Vnode> redirect;
316         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
317         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
318         vnattr_t open_attr;
319         EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
320         EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
321     }
322 
323     // no read handler, write handler
324     {
325         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(nullptr, &DummyWriter));
326         vnattr_t attr;
327         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
328         EXPECT_EQ(V_TYPE_FILE | V_IWUSR, attr.mode);
329         EXPECT_EQ(1, attr.nlink);
330 
331         fbl::RefPtr<fs::Vnode> redirect;
332         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
333         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
334         vnattr_t open_attr;
335         EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
336         EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
337     }
338 
339     // read handler, write handler
340     {
341         auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader, &DummyWriter));
342         vnattr_t attr;
343         EXPECT_EQ(ZX_OK, file->Getattr(&attr));
344         EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode);
345         EXPECT_EQ(1, attr.nlink);
346 
347         fbl::RefPtr<fs::Vnode> redirect;
348         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
349         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
350         vnattr_t open_attr;
351         EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
352         EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
353     }
354 
355     END_TEST;
356 }
357 
TestReadBuffered()358 bool TestReadBuffered() {
359     BEGIN_TEST;
360 
361     VectorReader reader{"first", "second", "",
362                         fbl::String(fbl::StringPiece("null\0null", 9u))};
363     auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(reader.GetHandler()));
364 
365     {
366         fbl::RefPtr<fs::Vnode> redirect;
367         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
368         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
369         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 0u, 0u, ""));
370         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, "firs"));
371         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, "rst"));
372         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 5u, 0u, "first"));
373         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 8u, 0u, "first"));
374         EXPECT_EQ(ZX_OK, redirect->Close());
375     }
376 
377     {
378         fbl::RefPtr<fs::Vnode> redirect;
379         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
380         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
381         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, "cond"));
382         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 6u, 0u, "second"));
383         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 8u, 0u, "second"));
384         EXPECT_EQ(ZX_OK, redirect->Close());
385     }
386 
387     {
388         fbl::RefPtr<fs::Vnode> redirect;
389         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
390         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
391         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, ""));
392         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, ""));
393         EXPECT_EQ(ZX_OK, redirect->Close());
394     }
395 
396     {
397         fbl::RefPtr<fs::Vnode> redirect;
398         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
399         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 0u, 0u, ""));
400         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, "null"));
401         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, fbl::StringPiece("ll\0n", 4u)));
402         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 9u, 0u, fbl::StringPiece("null\0null", 9u)));
403         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 12u, 0u, fbl::StringPiece("null\0null", 9u)));
404         EXPECT_EQ(ZX_OK, redirect->Close());
405     }
406 
407     {
408         fbl::RefPtr<fs::Vnode> redirect;
409         EXPECT_EQ(ZX_ERR_IO, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
410     }
411 
412     END_TEST;
413 }
414 
TestReadUnbuffered()415 bool TestReadUnbuffered() {
416     BEGIN_TEST;
417 
418     VectorReader reader{"first", "second", "third", "fourth", "fifth", "",
419                         fbl::String(fbl::StringPiece("null\0null", 9u))};
420     auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(reader.GetHandler()));
421 
422     {
423         fbl::RefPtr<fs::Vnode> redirect;
424         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
425         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
426         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 0u, 0u, ""));
427         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, "seco"));
428         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, ""));
429         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 3u, 0u, "thi"));
430         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 6u, 0u, "fourth"));
431         EXPECT_EQ(ZX_OK, redirect->Close());
432     }
433 
434     {
435         fbl::RefPtr<fs::Vnode> redirect;
436         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
437         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
438         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 8u, 0u, "fifth"));
439         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, ""));
440         EXPECT_TRUE(CheckRead(redirect, ZX_OK, 12u, 0u, fbl::StringPiece("null\0null", 9u)));
441         EXPECT_TRUE(CheckRead(redirect, ZX_ERR_IO, 0u, 0u, ""));
442         EXPECT_EQ(ZX_OK, redirect->Close());
443     }
444 
445     END_TEST;
446 }
447 
TestWriteBuffered()448 bool TestWriteBuffered() {
449     BEGIN_TEST;
450 
451     VectorWriter writer(6u);
452     auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(nullptr, writer.GetHandler(), 10u));
453 
454     {
455         fbl::RefPtr<fs::Vnode> redirect;
456         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
457         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
458         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "fixx", 4u));
459         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "", 0u));
460         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 2u, "rst", 3u));
461         EXPECT_EQ(ZX_OK, redirect->Close());
462     }
463 
464     {
465         fbl::RefPtr<fs::Vnode> redirect;
466         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
467         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
468         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "second", 6u));
469         EXPECT_EQ(ZX_OK, redirect->Close());
470     }
471 
472     {
473         fbl::RefPtr<fs::Vnode> redirect;
474         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
475         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
476         EXPECT_EQ(ZX_OK, redirect->Close());
477     }
478 
479     {
480         fbl::RefPtr<fs::Vnode> redirect;
481         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
482         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
483         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "thxrxxx", 7u, 7u));
484         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 2u, "i", 1u));
485         EXPECT_EQ(ZX_OK, redirect->Truncate(4u));
486         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "d", 5u, 1u));
487         EXPECT_EQ(ZX_OK, redirect->Close());
488     }
489 
490     {
491         fbl::RefPtr<fs::Vnode> redirect;
492         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
493         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
494         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "null", 4u));
495         EXPECT_EQ(ZX_OK, redirect->Truncate(5u));
496         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "null", 9u, 4u));
497         EXPECT_EQ(ZX_OK, redirect->Close());
498     }
499 
500     {
501         fbl::RefPtr<fs::Vnode> redirect;
502         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
503         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
504         EXPECT_EQ(ZX_ERR_NO_SPACE, redirect->Truncate(11u));
505         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "too-long", 8u, 8u));
506         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "-off-the-end", 10u, 2u));
507         EXPECT_TRUE(CheckAppend(redirect, ZX_ERR_NO_SPACE, "-overflow", 0u, 0u));
508         EXPECT_EQ(ZX_OK, redirect->Close());
509     }
510 
511     {
512         fbl::RefPtr<fs::Vnode> redirect;
513         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
514         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
515         EXPECT_EQ(ZX_ERR_IO, redirect->Close());
516     }
517 
518     EXPECT_EQ(6u, writer.strings().size());
519     EXPECT_FSTR_EQ(writer.strings()[0], fbl::String("first"));
520     EXPECT_FSTR_EQ(writer.strings()[1], fbl::String("second"));
521     EXPECT_FSTR_EQ(writer.strings()[2], fbl::String(""));
522     EXPECT_FSTR_EQ(writer.strings()[3], fbl::String("third"));
523     EXPECT_FSTR_EQ(writer.strings()[4], fbl::String("null\0null", 9u));
524     EXPECT_FSTR_EQ(writer.strings()[5], fbl::String("too-long-o"));
525 
526     END_TEST;
527 }
528 
TestWriteUnbuffered()529 bool TestWriteUnbuffered() {
530     BEGIN_TEST;
531 
532     VectorWriter writer(12u);
533     auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(nullptr, writer.GetHandler()));
534 
535     {
536         fbl::RefPtr<fs::Vnode> redirect;
537         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
538         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
539         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "first", 5u));
540         EXPECT_TRUE(CheckWrite(redirect, ZX_ERR_NO_SPACE, 2u, "xxx", 0u));
541         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "second", 6u));
542         EXPECT_EQ(ZX_OK, redirect->Close());
543     }
544 
545     {
546         fbl::RefPtr<fs::Vnode> redirect;
547         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
548         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
549         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "", 0u));
550         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "third", 5u, 5u));
551         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, fbl::StringPiece("null\0null", 9u), 9u, 9u));
552         EXPECT_EQ(ZX_OK, redirect->Close());
553     }
554 
555     {
556         fbl::RefPtr<fs::Vnode> redirect;
557         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_TRUNCATE));
558         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_TRUNCATE, &redirect));
559         EXPECT_EQ(ZX_OK, redirect->Close());
560     }
561 
562     {
563         fbl::RefPtr<fs::Vnode> redirect;
564         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_CREATE));
565         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_CREATE, &redirect));
566         EXPECT_EQ(ZX_OK, redirect->Close());
567     }
568 
569     {
570         fbl::RefPtr<fs::Vnode> redirect;
571         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
572         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
573         EXPECT_EQ(ZX_OK, redirect->Truncate(0u));
574         EXPECT_EQ(ZX_OK, redirect->Close());
575     }
576 
577     {
578         fbl::RefPtr<fs::Vnode> redirect;
579         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
580         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
581         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "fourth", 6u, 6u));
582         EXPECT_EQ(ZX_OK, redirect->Close());
583     }
584 
585     {
586         fbl::RefPtr<fs::Vnode> redirect;
587         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
588         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
589         EXPECT_EQ(ZX_OK, redirect->Close());
590     }
591 
592     {
593         fbl::RefPtr<fs::Vnode> redirect;
594         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
595         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
596         EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "fifth", 5u, 5u));
597         EXPECT_EQ(ZX_ERR_INVALID_ARGS, redirect->Truncate(10u));
598         EXPECT_EQ(ZX_OK, redirect->Truncate(0u));
599         EXPECT_EQ(ZX_OK, redirect->Close());
600     }
601 
602     {
603         fbl::RefPtr<fs::Vnode> redirect;
604         EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
605         EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
606         EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "a long string", 13u));
607         EXPECT_EQ(ZX_OK, redirect->Truncate(0u));
608         EXPECT_EQ(ZX_ERR_IO, redirect->Close());
609     }
610 
611     EXPECT_EQ(12u, writer.strings().size());
612     EXPECT_FSTR_EQ(writer.strings()[0], fbl::String("first"));
613     EXPECT_FSTR_EQ(writer.strings()[1], fbl::String("second"));
614     EXPECT_FSTR_EQ(writer.strings()[2], fbl::String(""));
615     EXPECT_FSTR_EQ(writer.strings()[3], fbl::String("third"));
616     EXPECT_FSTR_EQ(writer.strings()[4], fbl::String("null\0null", 9u));
617     EXPECT_FSTR_EQ(writer.strings()[5], fbl::String(""));
618     EXPECT_FSTR_EQ(writer.strings()[6], fbl::String(""));
619     EXPECT_FSTR_EQ(writer.strings()[7], fbl::String(""));
620     EXPECT_FSTR_EQ(writer.strings()[8], fbl::String("fourth"));
621     EXPECT_FSTR_EQ(writer.strings()[9], fbl::String("fifth"));
622     EXPECT_FSTR_EQ(writer.strings()[10], fbl::String(""));
623     EXPECT_FSTR_EQ(writer.strings()[11], fbl::String("a long string"));
624 
625     END_TEST;
626 }
627 
628 } // namespace
629 
630 BEGIN_TEST_CASE(pseudo_file_tests)
631 RUN_TEST(TestOpenValidationBuffered)
632 RUN_TEST(TestOpenValidationUnbuffered)
633 RUN_TEST(TestGetattrBuffered)
634 RUN_TEST(TestGetattrUnbuffered)
635 RUN_TEST(TestReadBuffered)
636 RUN_TEST(TestReadUnbuffered)
637 RUN_TEST(TestWriteBuffered)
638 RUN_TEST(TestWriteUnbuffered)
639 END_TEST_CASE(pseudo_file_tests)
640