1 // Copyright 2016 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 <time.h>
6
7 #include <fbl/alloc_checker.h>
8 #include <fbl/unique_ptr.h>
9
10 #include "util.h"
11
12 static unsigned count = 0;
13 template <size_t WriteOffset, size_t ReadOffset, size_t WriteSize>
test_sparse(void)14 bool test_sparse(void) {
15 BEGIN_TEST;
16
17 char filename[20];
18 sprintf(filename, "::my_file_%u", count++);
19
20 int fd = emu_open(filename, O_RDWR | O_CREAT, 0644);
21 ASSERT_GT(fd, 0);
22
23 // Create a random write buffer of data
24 fbl::AllocChecker ac;
25 fbl::unique_ptr<uint8_t[]> wbuf(new (&ac) uint8_t[WriteSize]);
26 ASSERT_EQ(ac.check(), true);
27 unsigned int seed = static_cast<unsigned int>(time(NULL));
28 unittest_printf("Sparse test using seed: %u\n", seed);
29 for (size_t i = 0; i < WriteSize; i++) {
30 wbuf[i] = (uint8_t) rand_r(&seed);
31 }
32
33 // Dump write buffer to file
34 ASSERT_EQ(emu_pwrite(fd, &wbuf[0], WriteSize, WriteOffset), WriteSize);
35 // Reopen file
36 ASSERT_EQ(emu_close(fd), 0);
37 fd = emu_open(filename, O_RDWR, 0644);
38 ASSERT_GT(fd, 0);
39
40 // Access read buffer from file
41 constexpr size_t kFileSize = WriteOffset + WriteSize;
42 constexpr size_t kBytesToRead = (kFileSize - ReadOffset) > WriteSize ?
43 WriteSize : (kFileSize - ReadOffset);
44 static_assert(kBytesToRead > 0, "We want to test writing AND reading");
45 fbl::unique_ptr<uint8_t[]> rbuf(new (&ac) uint8_t[kBytesToRead]);
46 ASSERT_EQ(ac.check(), true);
47 ASSERT_EQ(emu_pread(fd, &rbuf[0], kBytesToRead, ReadOffset), kBytesToRead);
48
49 constexpr size_t kSparseLength = (ReadOffset < WriteOffset) ?
50 WriteOffset - ReadOffset : 0;
51
52 if (kSparseLength > 0) {
53 for (size_t i = 0; i < kSparseLength; i++) {
54 ASSERT_EQ(rbuf[i], 0, "This portion of file should be sparse; but isn't");
55 }
56 }
57
58 constexpr size_t kWbufOffset = (ReadOffset < WriteOffset) ?
59 0 : ReadOffset - WriteOffset;
60 constexpr size_t kValidLength = kBytesToRead - kSparseLength;
61
62 if (kValidLength > 0) {
63 for (size_t i = 0; i < kValidLength; i++) {
64 ASSERT_EQ(rbuf[kSparseLength + i], wbuf[kWbufOffset + i]);
65 }
66 }
67
68 ASSERT_EQ(emu_close(fd), 0);
69 ASSERT_EQ(run_fsck(), 0);
70 END_TEST;
71 }
72
73 constexpr size_t kBlockSize = 8192;
74 constexpr size_t kDirectBlocks = 16;
75
76 RUN_MINFS_TESTS(sparse_tests,
77 RUN_TEST_MEDIUM((test_sparse<0, 0, kBlockSize>))
78 RUN_TEST_MEDIUM((test_sparse<kBlockSize / 2, 0, kBlockSize>))
79 RUN_TEST_MEDIUM((test_sparse<kBlockSize / 2, kBlockSize, kBlockSize>))
80 RUN_TEST_MEDIUM((test_sparse<kBlockSize, 0, kBlockSize>))
81 RUN_TEST_MEDIUM((test_sparse<kBlockSize, kBlockSize / 2, kBlockSize>))
82
83 RUN_TEST_MEDIUM((test_sparse<kBlockSize * kDirectBlocks,
84 kBlockSize * kDirectBlocks - kBlockSize,
85 kBlockSize * 2>))
86 RUN_TEST_MEDIUM((test_sparse<kBlockSize * kDirectBlocks,
87 kBlockSize * kDirectBlocks - kBlockSize,
88 kBlockSize * 32>))
89 RUN_TEST_MEDIUM((test_sparse<kBlockSize * kDirectBlocks + kBlockSize,
90 kBlockSize * kDirectBlocks - kBlockSize,
91 kBlockSize * 32>))
92 RUN_TEST_MEDIUM((test_sparse<kBlockSize * kDirectBlocks + kBlockSize,
93 kBlockSize * kDirectBlocks + 2 * kBlockSize,
94 kBlockSize * 32>))
95 )
96