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