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/vmo-file.h>
6 
7 #include <limits.h>
8 
9 #include <fuchsia/io/c/fidl.h>
10 #include <zircon/syscalls.h>
11 #include <zircon/syscalls/object.h>
12 
13 #include <unittest/unittest.h>
14 #include <lib/zx/vmo.h>
15 
16 namespace {
17 
18 constexpr size_t VMO_SIZE = PAGE_SIZE * 3u;
19 constexpr size_t PAGE_0 = 0u;
20 constexpr size_t PAGE_1 = PAGE_SIZE;
21 constexpr size_t PAGE_2 = PAGE_SIZE * 2u;
22 
GetKoid(zx_handle_t handle)23 zx_koid_t GetKoid(zx_handle_t handle) {
24     zx_info_handle_basic_t info;
25     zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
26                                             sizeof(info), nullptr, nullptr);
27     return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
28 }
29 
GetRights(zx_handle_t handle)30 zx_rights_t GetRights(zx_handle_t handle) {
31     zx_info_handle_basic_t info;
32     zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
33                                             sizeof(info), nullptr, nullptr);
34     return status == ZX_OK ? info.rights : 0u;
35 }
36 
FillVmo(const zx::vmo & vmo,size_t offset,size_t length,uint8_t byte)37 bool FillVmo(const zx::vmo& vmo, size_t offset, size_t length, uint8_t byte) {
38     BEGIN_HELPER;
39 
40     uint8_t data[length];
41     memset(data, byte, length);
42 
43     zx_status_t status = vmo.write(data, offset, length);
44     ASSERT_EQ(ZX_OK, status);
45 
46     END_HELPER;
47 }
48 
CheckVmo(const zx::vmo & vmo,size_t offset,size_t length,uint8_t expected_byte)49 bool CheckVmo(const zx::vmo& vmo, size_t offset, size_t length, uint8_t expected_byte) {
50     BEGIN_HELPER;
51 
52     uint8_t data[length];
53 
54     zx_status_t status = vmo.read(data, offset, length);
55     ASSERT_EQ(ZX_OK, status);
56 
57     for (size_t i = 0; i < length; i++) {
58         ASSERT_EQ(expected_byte, data[i]);
59     }
60 
61     END_HELPER;
62 }
63 
CheckData(uint8_t * data,size_t offset,size_t length,uint8_t expected_byte)64 bool CheckData(uint8_t* data, size_t offset, size_t length, uint8_t expected_byte) {
65     BEGIN_HELPER;
66 
67     for (size_t i = 0; i < length; i++) {
68         ASSERT_EQ(expected_byte, data[i + offset]);
69     }
70 
71     END_HELPER;
72 }
73 
CreateVmoABC(zx::vmo * out_vmo)74 bool CreateVmoABC(zx::vmo* out_vmo) {
75     BEGIN_HELPER;
76 
77     zx_status_t status = zx::vmo::create(VMO_SIZE, 0u, out_vmo);
78     ASSERT_EQ(ZX_OK, status);
79 
80     ASSERT_TRUE(FillVmo(*out_vmo, PAGE_0, PAGE_SIZE, 'A'));
81     ASSERT_TRUE(FillVmo(*out_vmo, PAGE_1, PAGE_SIZE, 'B'));
82     ASSERT_TRUE(FillVmo(*out_vmo, PAGE_2, PAGE_SIZE, 'C'));
83 
84     END_HELPER;
85 }
86 
TestConstructor()87 bool TestConstructor() {
88     BEGIN_TEST;
89 
90     zx::vmo abc;
91     ASSERT_TRUE(CreateVmoABC(&abc));
92 
93     // default parameters
94     {
95         fs::VmoFile file(abc, 0u, PAGE_SIZE);
96         EXPECT_EQ(abc.get(), file.vmo_handle());
97         EXPECT_EQ(0u, file.offset());
98         EXPECT_EQ(PAGE_SIZE, file.length());
99         EXPECT_FALSE(file.is_writable());
100         EXPECT_EQ(fs::VmoFile::VmoSharing::DUPLICATE, file.vmo_sharing());
101     }
102 
103     // everything explicit
104     {
105         fs::VmoFile file(abc, 3u, PAGE_2 + 1u, true, fs::VmoFile::VmoSharing::CLONE_COW);
106         EXPECT_EQ(abc.get(), file.vmo_handle());
107         EXPECT_EQ(3u, file.offset());
108         EXPECT_EQ(PAGE_2 + 1u, file.length());
109         EXPECT_TRUE(file.is_writable());
110         EXPECT_EQ(fs::VmoFile::VmoSharing::CLONE_COW, file.vmo_sharing());
111     }
112 
113     END_TEST;
114 }
115 
TestOpen()116 bool TestOpen() {
117     BEGIN_TEST;
118 
119     zx::vmo abc;
120     ASSERT_TRUE(CreateVmoABC(&abc));
121 
122     // read-only
123     {
124         fs::VmoFile file(abc, 0u, 0u);
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_NULL(redirect);
129         EXPECT_EQ(ZX_ERR_ACCESS_DENIED,
130                   file.ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
131         EXPECT_NULL(redirect);
132         EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file.ValidateFlags(ZX_FS_RIGHT_WRITABLE));
133         EXPECT_NULL(redirect);
134         EXPECT_EQ(ZX_ERR_NOT_DIR, file.ValidateFlags(ZX_FS_FLAG_DIRECTORY));
135         EXPECT_NULL(redirect);
136     }
137 
138     // writable
139     {
140         fs::VmoFile file(abc, 0u, 0u, true);
141         fbl::RefPtr<fs::Vnode> redirect;
142         EXPECT_EQ(ZX_OK, file.ValidateFlags(ZX_FS_RIGHT_READABLE));
143         EXPECT_EQ(ZX_OK, file.Open(ZX_FS_RIGHT_READABLE, &redirect));
144         EXPECT_NULL(redirect);
145         EXPECT_EQ(ZX_OK, file.ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
146         EXPECT_EQ(ZX_OK, file.Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
147         EXPECT_NULL(redirect);
148         EXPECT_EQ(ZX_OK, file.ValidateFlags(ZX_FS_RIGHT_WRITABLE));
149         EXPECT_EQ(ZX_OK, file.Open(ZX_FS_RIGHT_WRITABLE, &redirect));
150         EXPECT_NULL(redirect);
151         EXPECT_EQ(ZX_ERR_NOT_DIR, file.ValidateFlags(ZX_FS_FLAG_DIRECTORY));
152         EXPECT_NULL(redirect);
153     }
154 
155     END_TEST;
156 }
157 
TestRead()158 bool TestRead() {
159     BEGIN_TEST;
160 
161     zx::vmo abc;
162     ASSERT_TRUE(CreateVmoABC(&abc));
163 
164     uint8_t data[VMO_SIZE];
165     memset(data, 0, VMO_SIZE);
166 
167     // empty read of non-empty file
168     {
169         fs::VmoFile file(abc, 0u, PAGE_SIZE);
170         size_t actual = UINT64_MAX;
171         EXPECT_EQ(ZX_OK, file.Read(data, 0u, 0u, &actual));
172         EXPECT_EQ(0u, actual);
173     }
174 
175     // non-empty read of empty file
176     {
177         fs::VmoFile file(abc, 0u, 0u);
178         size_t actual = UINT64_MAX;
179         EXPECT_EQ(ZX_OK, file.Read(data, 1u, 0u, &actual));
180         EXPECT_EQ(0u, actual);
181     }
182 
183     // empty read at end of file
184     {
185         fs::VmoFile file(abc, 0u, 10u);
186         size_t actual = UINT64_MAX;
187         EXPECT_EQ(ZX_OK, file.Read(data, 0u, 10u, &actual));
188         EXPECT_EQ(0u, actual);
189     }
190 
191     // non-empty read at end of file
192     {
193         fs::VmoFile file(abc, 0u, 10u);
194         size_t actual = UINT64_MAX;
195         EXPECT_EQ(ZX_OK, file.Read(data, 1u, 10u, &actual));
196         EXPECT_EQ(0u, actual);
197     }
198 
199     // empty read beyond end of file
200     {
201         fs::VmoFile file(abc, 0u, 10u);
202         size_t actual = UINT64_MAX;
203         EXPECT_EQ(ZX_OK, file.Read(data, 0u, 11u, &actual));
204         EXPECT_EQ(0u, actual);
205     }
206 
207     // non-empty read beyond end of file
208     {
209         fs::VmoFile file(abc, 0u, 10u);
210         size_t actual = UINT64_MAX;
211         EXPECT_EQ(ZX_OK, file.Read(data, 1u, 11u, &actual));
212         EXPECT_EQ(0u, actual);
213     }
214 
215     // short read of non-empty file
216     {
217         fs::VmoFile file(abc, PAGE_1 - 3u, 10u);
218         size_t actual = UINT64_MAX;
219         EXPECT_EQ(ZX_OK, file.Read(data, 11u, 1u, &actual));
220         EXPECT_EQ(9u, actual);
221         EXPECT_TRUE(CheckData(data, 0u, 2u, 'A'));
222         EXPECT_TRUE(CheckData(data, 2u, 7u, 'B'));
223     }
224 
225     // full read
226     {
227         fs::VmoFile file(abc, 0u, VMO_SIZE);
228         size_t actual = UINT64_MAX;
229         EXPECT_EQ(ZX_OK, file.Read(data, VMO_SIZE, 0u, &actual));
230         EXPECT_EQ(VMO_SIZE, actual);
231         EXPECT_TRUE(CheckData(data, PAGE_0, PAGE_SIZE, 'A'));
232         EXPECT_TRUE(CheckData(data, PAGE_1, PAGE_SIZE, 'B'));
233         EXPECT_TRUE(CheckData(data, PAGE_2, PAGE_SIZE, 'C'));
234     }
235 
236     END_TEST;
237 }
238 
TestWrite()239 bool TestWrite() {
240     BEGIN_TEST;
241 
242     zx::vmo abc;
243     ASSERT_TRUE(CreateVmoABC(&abc));
244 
245     uint8_t data[VMO_SIZE];
246     memset(data, '!', VMO_SIZE);
247 
248     // empty write of non-empty file
249     {
250         fs::VmoFile file(abc, 0u, PAGE_SIZE, true);
251         size_t actual = UINT64_MAX;
252         EXPECT_EQ(ZX_OK, file.Write(data, 0u, 0u, &actual));
253         EXPECT_EQ(0u, actual);
254         EXPECT_TRUE(CheckVmo(abc, PAGE_0, PAGE_SIZE, 'A'));
255         EXPECT_TRUE(CheckVmo(abc, PAGE_1, PAGE_SIZE, 'B'));
256         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
257     }
258 
259     // non-empty write of empty file
260     {
261         fs::VmoFile file(abc, 0u, 0u, true);
262         size_t actual = UINT64_MAX;
263         EXPECT_EQ(ZX_ERR_NO_SPACE, file.Write(data, 1u, 0u, &actual));
264     }
265 
266     // empty write at end of file
267     {
268         fs::VmoFile file(abc, 0u, 10u, true);
269         size_t actual = UINT64_MAX;
270         EXPECT_EQ(ZX_OK, file.Write(data, 0u, 10u, &actual));
271         EXPECT_EQ(0u, actual);
272         EXPECT_TRUE(CheckVmo(abc, PAGE_0, PAGE_SIZE, 'A'));
273         EXPECT_TRUE(CheckVmo(abc, PAGE_1, PAGE_SIZE, 'B'));
274         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
275     }
276 
277     // non-empty write at end of file
278     {
279         fs::VmoFile file(abc, 0u, 10u, true);
280         size_t actual = UINT64_MAX;
281         EXPECT_EQ(ZX_ERR_NO_SPACE, file.Write(data, 1u, 10u, &actual));
282     }
283 
284     // empty write beyond end of file
285     {
286         fs::VmoFile file(abc, 0u, 10u, true);
287         size_t actual = UINT64_MAX;
288         EXPECT_EQ(ZX_OK, file.Write(data, 0u, 11u, &actual));
289         EXPECT_EQ(0u, actual);
290         EXPECT_TRUE(CheckVmo(abc, PAGE_0, PAGE_SIZE, 'A'));
291         EXPECT_TRUE(CheckVmo(abc, PAGE_1, PAGE_SIZE, 'B'));
292         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
293     }
294 
295     // non-empty write beyond end of file
296     {
297         fs::VmoFile file(abc, 0u, 10u, true);
298         size_t actual = UINT64_MAX;
299         EXPECT_EQ(ZX_ERR_NO_SPACE, file.Write(data, 1u, 11u, &actual));
300     }
301 
302     // short write of non-empty file
303     {
304         fs::VmoFile file(abc, PAGE_1 - 3u, 10u, true);
305         size_t actual = UINT64_MAX;
306         EXPECT_EQ(ZX_OK, file.Write(data, 11u, 1u, &actual));
307         EXPECT_EQ(9u, actual);
308         EXPECT_TRUE(CheckVmo(abc, PAGE_0, PAGE_SIZE - 2u, 'A'));
309         EXPECT_TRUE(CheckVmo(abc, PAGE_1 - 2u, 9u, '!'));
310         EXPECT_TRUE(CheckVmo(abc, PAGE_1 + 7u, PAGE_SIZE - 7u, 'B'));
311         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
312     }
313 
314     // full write
315     {
316         fs::VmoFile file(abc, 0u, VMO_SIZE, true);
317         size_t actual = UINT64_MAX;
318         EXPECT_EQ(ZX_OK, file.Write(data, VMO_SIZE, 0u, &actual));
319         EXPECT_EQ(VMO_SIZE, actual);
320         EXPECT_TRUE(CheckVmo(abc, 0u, VMO_SIZE, '!'));
321     }
322 
323     END_TEST;
324 }
325 
TestGetattr()326 bool TestGetattr() {
327     BEGIN_TEST;
328 
329     zx::vmo abc;
330     ASSERT_TRUE(CreateVmoABC(&abc));
331 
332     // read-only
333     {
334         fs::VmoFile file(abc, 0u, PAGE_SIZE * 3u + 117u);
335         vnattr_t attr;
336         EXPECT_EQ(ZX_OK, file.Getattr(&attr));
337         EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode);
338         EXPECT_EQ(PAGE_SIZE * 3u + 117u, attr.size);
339         EXPECT_EQ(PAGE_SIZE, attr.blksize);
340         EXPECT_EQ(4u * PAGE_SIZE / VNATTR_BLKSIZE, attr.blkcount);
341         EXPECT_EQ(1u, attr.nlink);
342     }
343 
344     // writable
345     {
346         fs::VmoFile file(abc, 0u, PAGE_SIZE * 3u + 117u, true);
347         vnattr_t attr;
348         EXPECT_EQ(ZX_OK, file.Getattr(&attr));
349         EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode);
350         EXPECT_EQ(PAGE_SIZE * 3u + 117u, attr.size);
351         EXPECT_EQ(PAGE_SIZE, attr.blksize);
352         EXPECT_EQ(4u * PAGE_SIZE / VNATTR_BLKSIZE, attr.blkcount);
353         EXPECT_EQ(1u, attr.nlink);
354     }
355 
356     END_TEST;
357 }
358 
TestGetHandles()359 bool TestGetHandles() {
360     BEGIN_TEST;
361 
362     // sharing = VmoSharing::NONE
363     {
364         zx::vmo abc;
365         ASSERT_TRUE(CreateVmoABC(&abc));
366 
367         fuchsia_io_NodeInfo info;
368         fs::VmoFile file(abc, PAGE_1 - 5u, 23u, false, fs::VmoFile::VmoSharing::NONE);
369         EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, file.GetHandles(ZX_FS_RIGHT_READABLE, &info));
370     }
371 
372     // sharing = VmoSharing::DUPLICATE, read only
373     {
374         zx::vmo abc;
375         ASSERT_TRUE(CreateVmoABC(&abc));
376 
377         fuchsia_io_NodeInfo info;
378         fs::VmoFile file(abc, PAGE_1 - 5u, 23u, false, fs::VmoFile::VmoSharing::DUPLICATE);
379         EXPECT_EQ(ZX_OK, file.GetHandles(ZX_FS_RIGHT_READABLE, &info));
380         zx::vmo vmo(info.vmofile.vmo);
381         EXPECT_NE(abc.get(), vmo.get());
382         EXPECT_EQ(GetKoid(abc.get()), GetKoid(vmo.get()));
383         EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_EXECUTE,
384                   GetRights(vmo.get()));
385         EXPECT_EQ(fuchsia_io_NodeInfoTag_vmofile, info.tag);
386         EXPECT_EQ(PAGE_1 - 5u, info.vmofile.offset);
387         EXPECT_EQ(23u, info.vmofile.length);
388 
389         EXPECT_TRUE(CheckVmo(vmo, PAGE_1 - 5u, 5u, 'A'));
390         EXPECT_TRUE(CheckVmo(vmo, PAGE_1, 18u, 'B'));
391     }
392 
393     // sharing = VmoSharing::DUPLICATE, read-write
394     {
395         zx::vmo abc;
396         ASSERT_TRUE(CreateVmoABC(&abc));
397 
398         fuchsia_io_NodeInfo info;
399         fs::VmoFile file(abc, PAGE_1 - 5u, 23u, true, fs::VmoFile::VmoSharing::DUPLICATE);
400         EXPECT_EQ(ZX_OK, file.GetHandles(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &info));
401         zx::vmo vmo(info.vmofile.vmo);
402         EXPECT_NE(abc.get(), vmo.get());
403         EXPECT_EQ(GetKoid(abc.get()), GetKoid(vmo.get()));
404         EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE,
405                   GetRights(vmo.get()));
406         EXPECT_EQ(fuchsia_io_NodeInfoTag_vmofile, info.tag);
407         EXPECT_EQ(PAGE_1 - 5u, info.vmofile.offset);
408         EXPECT_EQ(23u, info.vmofile.length);
409 
410         EXPECT_TRUE(CheckVmo(vmo, PAGE_1 - 5u, 5u, 'A'));
411         EXPECT_TRUE(CheckVmo(vmo, PAGE_1, 18u, 'B'));
412 
413         EXPECT_TRUE(FillVmo(vmo, PAGE_1 - 5u, 23u, '!'));
414 
415         EXPECT_TRUE(CheckVmo(abc, 0u, PAGE_SIZE - 5u, 'A'));
416         EXPECT_TRUE(CheckVmo(abc, PAGE_1 - 5u, 23u, '!'));
417         EXPECT_TRUE(CheckVmo(abc, PAGE_1 + 18u, PAGE_SIZE - 18u, 'B'));
418         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
419     }
420 
421     // sharing = VmoSharing::DUPLICATE, write only
422     {
423         zx::vmo abc;
424         ASSERT_TRUE(CreateVmoABC(&abc));
425 
426         fuchsia_io_NodeInfo info;
427         fs::VmoFile file(abc, PAGE_1 - 5u, 23u, true, fs::VmoFile::VmoSharing::DUPLICATE);
428         EXPECT_EQ(ZX_OK, file.GetHandles(ZX_FS_RIGHT_WRITABLE, &info));
429         zx::vmo vmo(info.vmofile.vmo);
430         EXPECT_NE(abc.get(), vmo.get());
431         EXPECT_EQ(GetKoid(abc.get()), GetKoid(vmo.get()));
432         EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_WRITE,
433                   GetRights(vmo.get()));
434         EXPECT_EQ(fuchsia_io_NodeInfoTag_vmofile, info.tag);
435         EXPECT_EQ(PAGE_1 - 5u, info.vmofile.offset);
436         EXPECT_EQ(23u, info.vmofile.length);
437 
438         EXPECT_TRUE(FillVmo(vmo, PAGE_1 - 5u, 23u, '!'));
439 
440         EXPECT_TRUE(CheckVmo(abc, 0u, PAGE_SIZE - 5u, 'A'));
441         EXPECT_TRUE(CheckVmo(abc, PAGE_1 - 5u, 23u, '!'));
442         EXPECT_TRUE(CheckVmo(abc, PAGE_1 + 18u, PAGE_SIZE - 18u, 'B'));
443         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
444     }
445 
446     // sharing = VmoSharing::CLONE_COW, read only
447     {
448         zx::vmo abc;
449         ASSERT_TRUE(CreateVmoABC(&abc));
450 
451         fuchsia_io_NodeInfo info;
452         fs::VmoFile file(abc, PAGE_2 - 5u, 23u, false, fs::VmoFile::VmoSharing::CLONE_COW);
453         EXPECT_EQ(ZX_OK, file.GetHandles(ZX_FS_RIGHT_READABLE, &info));
454         zx::vmo vmo(info.vmofile.vmo);
455         EXPECT_NE(abc.get(), vmo.get());
456         EXPECT_NE(GetKoid(abc.get()), GetKoid(vmo.get()));
457         EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_EXECUTE,
458                   GetRights(vmo.get()));
459         EXPECT_EQ(fuchsia_io_NodeInfoTag_vmofile, info.tag);
460         EXPECT_EQ(PAGE_SIZE - 5u, info.vmofile.offset);
461         EXPECT_EQ(23u, info.vmofile.length);
462 
463         EXPECT_TRUE(CheckVmo(vmo, PAGE_SIZE - 5u, 5u, 'B'));
464         EXPECT_TRUE(CheckVmo(vmo, PAGE_SIZE, 18u, 'C'));
465     }
466 
467     // sharing = VmoSharing::CLONE_COW, read-write
468     {
469         zx::vmo abc;
470         ASSERT_TRUE(CreateVmoABC(&abc));
471 
472         fuchsia_io_NodeInfo info;
473         fs::VmoFile file(abc, PAGE_2 - 5u, 23u, true, fs::VmoFile::VmoSharing::CLONE_COW);
474         EXPECT_EQ(ZX_OK, file.GetHandles(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &info));
475         zx::vmo vmo(info.vmofile.vmo);
476         EXPECT_NE(abc.get(), vmo.get());
477         EXPECT_NE(GetKoid(abc.get()), GetKoid(vmo.get()));
478         EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE,
479                   GetRights(vmo.get()));
480         EXPECT_EQ(fuchsia_io_NodeInfoTag_vmofile, info.tag);
481         EXPECT_EQ(PAGE_SIZE - 5u, info.vmofile.offset);
482         EXPECT_EQ(23u, info.vmofile.length);
483 
484         EXPECT_TRUE(CheckVmo(vmo, PAGE_SIZE - 5u, 5u, 'B'));
485         EXPECT_TRUE(CheckVmo(vmo, PAGE_SIZE, 18u, 'C'));
486 
487         EXPECT_TRUE(FillVmo(vmo, PAGE_SIZE - 5u, 23u, '!'));
488 
489         EXPECT_TRUE(CheckVmo(abc, PAGE_0, PAGE_SIZE, 'A'));
490         EXPECT_TRUE(CheckVmo(abc, PAGE_1, PAGE_SIZE, 'B'));
491         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
492     }
493 
494     // sharing = VmoSharing::CLONE_COW, write only
495     {
496         zx::vmo abc;
497         ASSERT_TRUE(CreateVmoABC(&abc));
498 
499         fuchsia_io_NodeInfo info;
500         fs::VmoFile file(abc, PAGE_2 - 5u, 23u, true, fs::VmoFile::VmoSharing::CLONE_COW);
501         EXPECT_EQ(ZX_OK, file.GetHandles(ZX_FS_RIGHT_WRITABLE, &info));
502         zx::vmo vmo(info.vmofile.vmo);
503         EXPECT_NE(abc.get(), vmo.get());
504         EXPECT_NE(GetKoid(abc.get()), GetKoid(vmo.get()));
505         EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_WRITE,
506                   GetRights(vmo.get()));
507         EXPECT_EQ(fuchsia_io_NodeInfoTag_vmofile, info.tag);
508         EXPECT_EQ(PAGE_SIZE - 5u, info.vmofile.offset);
509         EXPECT_EQ(23u, info.vmofile.length);
510 
511         EXPECT_TRUE(FillVmo(vmo, PAGE_SIZE - 5u, 23u, '!'));
512 
513         EXPECT_TRUE(CheckVmo(abc, PAGE_0, PAGE_SIZE, 'A'));
514         EXPECT_TRUE(CheckVmo(abc, PAGE_1, PAGE_SIZE, 'B'));
515         EXPECT_TRUE(CheckVmo(abc, PAGE_2, PAGE_SIZE, 'C'));
516     }
517 
518     END_TEST;
519 }
520 
521 } // namespace
522 
523 BEGIN_TEST_CASE(vmo_file_tests)
524 RUN_TEST(TestConstructor)
525 RUN_TEST(TestOpen)
526 RUN_TEST(TestRead)
527 RUN_TEST(TestWrite)
528 RUN_TEST(TestGetattr)
529 RUN_TEST(TestGetHandles)
530 END_TEST_CASE(vmo_file_tests)
531