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