1 // Copyright 2018 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 <assert.h>
6 #include <fcntl.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13
14 #include <fbl/algorithm.h>
15 #include <fbl/alloc_checker.h>
16 #include <fbl/unique_fd.h>
17 #include <fbl/unique_ptr.h>
18 #include <zircon/syscalls.h>
19
20 #include "filesystems.h"
21 #include "misc.h"
22
23 namespace {
24
25 // Test that zero length read and write operations are valid.
TestZeroLengthOperations(void)26 bool TestZeroLengthOperations(void) {
27 BEGIN_TEST;
28
29 const char* filename = "::zero_length_ops";
30 fbl::unique_fd fd(open(filename, O_RDWR | O_CREAT, 0644));
31 ASSERT_TRUE(fd);
32
33 // Zero-length write.
34 ASSERT_EQ(write(fd.get(), NULL, 0), 0);
35 ASSERT_EQ(pwrite(fd.get(), NULL, 0, 0), 0);
36
37 // Zero-length read.
38 ASSERT_EQ(read(fd.get(), NULL, 0), 0);
39 ASSERT_EQ(pread(fd.get(), NULL, 0, 0), 0);
40
41 // Seek pointer unchanged.
42 ASSERT_EQ(lseek(fd.get(), 0, SEEK_CUR), 0);
43
44 ASSERT_EQ(close(fd.release()), 0);
45 ASSERT_EQ(unlink(filename), 0);
46
47 END_TEST;
48 }
49
50 // Test that non-zero length read_at and write_at operations are valid.
TestOffsetOperations(void)51 bool TestOffsetOperations(void) {
52 BEGIN_TEST;
53
54 srand(0xDEADBEEF);
55
56 constexpr size_t kBufferSize = PAGE_SIZE;
57 uint8_t expected[kBufferSize];
58 for (size_t i = 0; i < fbl::count_of(expected); i++) {
59 expected[i] = static_cast<uint8_t>(rand());
60 }
61
62 struct TestOption {
63 size_t write_start;
64 size_t read_start;
65 size_t expected_read_length;
66 };
67
68 TestOption options[] = {
69 {0, 0, kBufferSize},
70 {0, 1, kBufferSize - 1},
71 {1, 0, kBufferSize},
72 {1, 1, kBufferSize},
73 };
74
75 for (const auto& opt : options) {
76 const char* filename = "::offset_ops";
77 fbl::unique_fd fd(open(filename, O_RDWR | O_CREAT, 0644));
78 ASSERT_TRUE(fd);
79
80 uint8_t buf[kBufferSize];
81 memset(buf, 0, sizeof(buf));
82
83 // 1) Write "kBufferSize" bytes at opt.write_start
84 ASSERT_EQ(pwrite(fd.get(), expected, sizeof(expected), opt.write_start),
85 sizeof(expected));
86
87 // 2) Read "kBufferSize" bytes at opt.read_start;
88 // actually read opt.expected_read_length bytes.
89 ASSERT_EQ(pread(fd.get(), buf, sizeof(expected), opt.read_start),
90 static_cast<ssize_t>(opt.expected_read_length));
91
92 // 3) Verify the contents of the read matched, the seek
93 // pointer is unchanged, and the file size is correct.
94 if (opt.write_start <= opt.read_start) {
95 size_t read_skip = opt.read_start - opt.write_start;
96 ASSERT_EQ(memcmp(buf, expected + read_skip, opt.expected_read_length), 0);
97 } else {
98 size_t write_skip = opt.write_start - opt.read_start;
99 uint8_t zeroes[write_skip];
100 memset(zeroes, 0, sizeof(zeroes));
101 ASSERT_EQ(memcmp(buf, zeroes, write_skip), 0);
102 }
103 ASSERT_EQ(lseek(fd.get(), 0, SEEK_CUR), 0);
104 struct stat st;
105 ASSERT_EQ(fstat(fd.get(), &st), 0);
106 ASSERT_EQ(st.st_size, static_cast<ssize_t>(opt.write_start + sizeof(expected)));
107
108 ASSERT_EQ(close(fd.release()), 0);
109 ASSERT_EQ(unlink(filename), 0);
110 }
111
112 END_TEST;
113 }
114
115 } // namespace
116
117 RUN_FOR_ALL_FILESYSTEMS(rw_tests,
118 RUN_TEST_MEDIUM(TestZeroLengthOperations)
119 RUN_TEST_MEDIUM(TestOffsetOperations)
120 )
121