Newer
Older
minerva / Tests / Kernel / TestExt2FS.cpp
@minerva minerva on 13 Jul 3 KB Initial commit
/*
 * Copyright (c) 2023, Tim Ledbetter <timledbetter@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#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)
{
    static constexpr auto TEST_FILE_PATH = "/home/anon/.ext2_test";

    auto uid = geteuid();
    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);
    });

    EXPECT_EQ(setuid(0), 0);
    EXPECT_EQ(fchown(fd, 65536, 65536), 0);

    struct stat st;
    EXPECT_EQ(fstat(fd, &st), 0);
    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);
}