blob: ef376cf5c0fa665a4d093490d8eb2aadfc7927a4 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <assert.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <zircon/syscalls.h>
#include <fbl/algorithm.h>
#include <fbl/alloc_checker.h>
#include <fbl/unique_fd.h>
#include "filesystems.h"
#include "misc.h"
namespace {
// Test that zero length read and write operations are valid.
bool TestZeroLengthOperations(void) {
BEGIN_TEST;
const char* filename = "::zero_length_ops";
fbl::unique_fd fd(open(filename, O_RDWR | O_CREAT, 0644));
ASSERT_TRUE(fd);
// Zero-length write.
ASSERT_EQ(write(fd.get(), NULL, 0), 0);
ASSERT_EQ(pwrite(fd.get(), NULL, 0, 0), 0);
// Zero-length read.
ASSERT_EQ(read(fd.get(), NULL, 0), 0);
ASSERT_EQ(pread(fd.get(), NULL, 0, 0), 0);
// Seek pointer unchanged.
ASSERT_EQ(lseek(fd.get(), 0, SEEK_CUR), 0);
ASSERT_EQ(close(fd.release()), 0);
ASSERT_EQ(unlink(filename), 0);
END_TEST;
}
// Test that non-zero length read_at and write_at operations are valid.
bool TestOffsetOperations(void) {
BEGIN_TEST;
srand(0xDEADBEEF);
constexpr size_t kBufferSize = PAGE_SIZE;
uint8_t expected[kBufferSize];
for (size_t i = 0; i < fbl::count_of(expected); i++) {
expected[i] = static_cast<uint8_t>(rand());
}
struct TestOption {
size_t write_start;
size_t read_start;
size_t expected_read_length;
};
TestOption options[] = {
{0, 0, kBufferSize},
{0, 1, kBufferSize - 1},
{1, 0, kBufferSize},
{1, 1, kBufferSize},
};
for (const auto& opt : options) {
const char* filename = "::offset_ops";
fbl::unique_fd fd(open(filename, O_RDWR | O_CREAT, 0644));
ASSERT_TRUE(fd);
uint8_t buf[kBufferSize];
memset(buf, 0, sizeof(buf));
// 1) Write "kBufferSize" bytes at opt.write_start
ASSERT_EQ(pwrite(fd.get(), expected, sizeof(expected), opt.write_start), sizeof(expected));
// 2) Read "kBufferSize" bytes at opt.read_start;
// actually read opt.expected_read_length bytes.
ASSERT_EQ(pread(fd.get(), buf, sizeof(expected), opt.read_start),
static_cast<ssize_t>(opt.expected_read_length));
// 3) Verify the contents of the read matched, the seek
// pointer is unchanged, and the file size is correct.
if (opt.write_start <= opt.read_start) {
size_t read_skip = opt.read_start - opt.write_start;
ASSERT_EQ(memcmp(buf, expected + read_skip, opt.expected_read_length), 0);
} else {
size_t write_skip = opt.write_start - opt.read_start;
uint8_t zeroes[write_skip];
memset(zeroes, 0, sizeof(zeroes));
ASSERT_EQ(memcmp(buf, zeroes, write_skip), 0);
}
ASSERT_EQ(lseek(fd.get(), 0, SEEK_CUR), 0);
struct stat st;
ASSERT_EQ(fstat(fd.get(), &st), 0);
ASSERT_EQ(st.st_size, static_cast<ssize_t>(opt.write_start + sizeof(expected)));
ASSERT_EQ(close(fd.release()), 0);
ASSERT_EQ(unlink(filename), 0);
}
END_TEST;
}
} // namespace
RUN_FOR_ALL_FILESYSTEMS(rw_tests, RUN_TEST_MEDIUM(TestZeroLengthOperations)
RUN_TEST_MEDIUM(TestOffsetOperations))