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