Tests/Kernel: Add test for Ext2FS reads and writes

This commit adds a new test case which carries out the following steps:
* write() to a block of an ext2 file, verify the write() was successful
* read() the same block back, verify the read() was successful
* verify that the data from the read() is identical to the data that was
  written in the write()

The test runs the above steps on the following blocks of an ext2 file:
* the first and last direct blocks
* the first and last singly indirect blocks
* the first and last doubly indirect blocks
* the first and last triply indirect blocks
This commit is contained in:
brody-qq 2024-07-14 23:42:00 +01:00 committed by Nico Weber
parent c247aac15e
commit e0242abf93

View file

@ -6,6 +6,9 @@
#include <LibTest/TestCase.h>
#include <fcntl.h>
#include <math.h>
#include <stdlib.h>
#include <sys/statvfs.h>
#include <unistd.h>
TEST_CASE(test_uid_and_gid_high_bits_are_set)
@ -16,6 +19,7 @@ TEST_CASE(test_uid_and_gid_high_bits_are_set)
EXPECT_EQ(uid, 0u);
auto fd = open(TEST_FILE_PATH, O_CREAT);
VERIFY(fd != -1);
auto cleanup_guard = ScopeGuard([&] {
close(fd);
unlink(TEST_FILE_PATH);
@ -29,3 +33,76 @@ TEST_CASE(test_uid_and_gid_high_bits_are_set)
EXPECT_EQ(st.st_uid, 65536u);
EXPECT_EQ(st.st_gid, 65536u);
}
TEST_CASE(test_ext2_writes_and_reads_to_block_ranges)
{
static constexpr auto TEST_FILE_PATH = "/home/anon/.ext2_test";
auto fd = open(TEST_FILE_PATH, O_RDWR | O_CREAT);
VERIFY(fd != -1);
auto cleanup_guard = ScopeGuard([&] {
close(fd);
unlink(TEST_FILE_PATH);
});
struct statvfs stvfs;
int rc = fstatvfs(fd, &stvfs);
VERIFY(rc != -1);
size_t block_size = (size_t)stvfs.f_bsize;
size_t ptrs_per_indirect_block = block_size / sizeof(u32);
size_t direct_block_count = 12;
size_t singly_indirect_block_count = ptrs_per_indirect_block;
size_t doubly_indirect_block_count = pow(ptrs_per_indirect_block, 2);
size_t triply_indirect_block_count = pow(ptrs_per_indirect_block, 3);
size_t direct_blocks_capacity = direct_block_count;
size_t singly_indirect_blocks_capacity = direct_blocks_capacity + singly_indirect_block_count;
size_t doubly_indirect_blocks_capacity = singly_indirect_blocks_capacity + doubly_indirect_block_count;
size_t triply_indirect_blocks_capacity = doubly_indirect_blocks_capacity + triply_indirect_block_count;
char* block_buf = (char*)malloc(block_size);
block_buf[0] = '!';
block_buf[block_size - 1] = '!';
char* read_buf = (char*)malloc(block_size);
auto malloc_cleanup_guard = ScopeGuard([&] {
free(block_buf);
free(read_buf);
});
auto write_then_read_block = [&](size_t block) {
size_t offset = block * block_size;
// write the block, and verify that write() was successful
off_t seek_rc = lseek(fd, offset, SEEK_SET);
VERIFY(seek_rc != -1);
int nwrite = write(fd, block_buf, block_size);
EXPECT((size_t)nwrite == block_size);
// read the block we just wrote, and verify that read() was successful
seek_rc = lseek(fd, offset, SEEK_SET);
VERIFY(seek_rc != -1);
int nread = read(fd, read_buf, block_size);
EXPECT((size_t)nread == block_size);
// verify that the block we read back is identical to the block we wrote
EXPECT(memcmp(read_buf, block_buf, block_size) == 0);
};
// run test on the first & last direct blocks
write_then_read_block(0);
write_then_read_block(direct_blocks_capacity - 1);
// run test on the first & last singly indirect blocks
write_then_read_block(direct_blocks_capacity);
write_then_read_block(singly_indirect_blocks_capacity - 1);
// run test on the first & last doubly indirect blocks
write_then_read_block(singly_indirect_blocks_capacity);
write_then_read_block(doubly_indirect_blocks_capacity - 1);
// run test on the first & last triply indirect blocks
write_then_read_block(doubly_indirect_blocks_capacity);
write_then_read_block(triply_indirect_blocks_capacity - 1);
}