236 lines
6.6 KiB
C
236 lines
6.6 KiB
C
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "test_fs.h"
|
|
|
|
// ============================================================================
|
|
// Helper function
|
|
// ============================================================================
|
|
|
|
static int create_file(const char *file_path) {
|
|
int fd;
|
|
int flags = O_WRONLY | O_CREAT | O_TRUNC;
|
|
int mode = 00666;
|
|
fd = open(file_path, flags, mode);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to create a file");
|
|
}
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
static int remove_file(const char *file_path) {
|
|
int ret;
|
|
ret = unlink(file_path);
|
|
if (ret < 0) {
|
|
THROW_ERROR("failed to unlink the created file");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test cases for truncate
|
|
// ============================================================================
|
|
|
|
static int __test_truncate(const char *file_path) {
|
|
int fd;
|
|
off_t len = 128;
|
|
|
|
fd = open(file_path, O_WRONLY);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open a file to truncate");
|
|
}
|
|
if (ftruncate(fd, len) < 0) {
|
|
THROW_ERROR("failed to call ftruncate");
|
|
}
|
|
struct stat stat_buf;
|
|
if (fstat(fd, &stat_buf) < 0) {
|
|
THROW_ERROR("failed to stat file");
|
|
}
|
|
if (stat_buf.st_size != len) {
|
|
THROW_ERROR("failed to check the len after ftruncate");
|
|
}
|
|
close(fd);
|
|
|
|
len = 256;
|
|
if (truncate(file_path, len) < 0) {
|
|
THROW_ERROR("failed to call truncate");
|
|
}
|
|
if (stat(file_path, &stat_buf) < 0) {
|
|
THROW_ERROR("failed to stat file");
|
|
}
|
|
if (stat_buf.st_size != len) {
|
|
THROW_ERROR("failed to check the len after truncate");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __test_open_truncate_existing_file(const char *file_path) {
|
|
char *write_str = "Hello World\n";
|
|
int fd;
|
|
|
|
fd = open(file_path, O_WRONLY);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open a file to write");
|
|
}
|
|
if (write(fd, write_str, strlen(write_str)) <= 0) {
|
|
THROW_ERROR("failed to write");
|
|
}
|
|
close(fd);
|
|
|
|
fd = open(file_path, O_RDWR | O_TRUNC);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open an existing file with O_TRUNC");
|
|
}
|
|
struct stat stat_buf;
|
|
if (fstat(fd, &stat_buf) < 0) {
|
|
THROW_ERROR("failed to stat file");
|
|
}
|
|
if (stat_buf.st_size != 0) {
|
|
THROW_ERROR("failed to check the len after open with O_TRUNC");
|
|
}
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __test_truncate_then_read(const char *file_path) {
|
|
size_t file_len = 32;
|
|
off_t small_len = 16;
|
|
off_t big_len = 48;
|
|
char read_buf[128] = { 0 };
|
|
int fd;
|
|
|
|
fd = open(file_path, O_RDWR);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open file");
|
|
}
|
|
|
|
// truncate to small length, then read
|
|
if (fill_file_with_repeated_bytes(fd, file_len, 0xfa) < 0) {
|
|
THROW_ERROR("");
|
|
}
|
|
if (ftruncate(fd, small_len) < 0) {
|
|
THROW_ERROR("failed to call ftruncate to small length");
|
|
}
|
|
if (lseek(fd, 0, SEEK_SET) < 0) {
|
|
THROW_ERROR("failed to call lseek");
|
|
}
|
|
if (read(fd, read_buf, sizeof(read_buf)) != small_len) {
|
|
THROW_ERROR("failed to check read with small length");
|
|
}
|
|
if (check_bytes_in_buf(read_buf, small_len, 0xfa) < 0) {
|
|
THROW_ERROR("failed to check the read buf after truncate with smaller length");
|
|
}
|
|
|
|
// truncate to big length, then check the file content between small length and big length
|
|
if (ftruncate(fd, big_len) < 0) {
|
|
THROW_ERROR("failed to call ftruncate");
|
|
}
|
|
if (lseek(fd, small_len, SEEK_SET) < 0) {
|
|
THROW_ERROR("failed to call lseek");
|
|
}
|
|
memset(read_buf, 0x00, sizeof(read_buf));
|
|
if (read(fd, read_buf, sizeof(read_buf)) != big_len - small_len) {
|
|
THROW_ERROR("failed to check read with big length");
|
|
}
|
|
if (check_bytes_in_buf(read_buf, big_len - small_len, 0x00) < 0) {
|
|
THROW_ERROR("failed to check the read buf after truncate with bigger lenghth");
|
|
}
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
static int __test_truncate_then_write(const char *file_path) {
|
|
size_t file_len = 32;
|
|
off_t small_len = 16;
|
|
char write_buf[16] = { 0 };
|
|
char read_buf[16] = { 0 };
|
|
int fd;
|
|
|
|
fd = open(file_path, O_RDWR);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open file");
|
|
}
|
|
|
|
// truncate file to small length, then write beyond the length
|
|
if (fill_file_with_repeated_bytes(fd, file_len, 0xfa) < 0) {
|
|
THROW_ERROR("");
|
|
}
|
|
if (ftruncate(fd, small_len) < 0) {
|
|
THROW_ERROR("failed to call ftruncate to small length");
|
|
}
|
|
if (lseek(fd, file_len, SEEK_SET) < 0) {
|
|
THROW_ERROR("failed to call lseek");
|
|
}
|
|
memset(write_buf, 0xaa, sizeof(write_buf));
|
|
if (write(fd, write_buf, sizeof(write_buf)) != sizeof(write_buf)) {
|
|
THROW_ERROR("failed to write buffer");
|
|
}
|
|
|
|
// check the file content between small length and old length
|
|
if (lseek(fd, small_len, SEEK_SET) < 0) {
|
|
THROW_ERROR("failed to call lseek");
|
|
}
|
|
if (read(fd, read_buf, sizeof(read_buf)) != file_len - small_len) {
|
|
THROW_ERROR("failed to read buf");
|
|
}
|
|
if (check_bytes_in_buf(read_buf, file_len - small_len, 0x00) < 0) {
|
|
THROW_ERROR("failed to check the read buf after write beyond the length");
|
|
}
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
typedef int(*test_file_func_t)(const char *);
|
|
|
|
static int test_file_framework(test_file_func_t fn) {
|
|
const char *file_path = "/root/test_filesystem_truncate.txt";
|
|
|
|
if (create_file(file_path) < 0) {
|
|
return -1;
|
|
}
|
|
if (fn(file_path) < 0) {
|
|
return -1;
|
|
}
|
|
if (remove_file(file_path) < 0) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int test_truncate() {
|
|
return test_file_framework(__test_truncate);
|
|
}
|
|
|
|
static int test_open_truncate_existing_file() {
|
|
return test_file_framework(__test_open_truncate_existing_file);
|
|
}
|
|
|
|
static int test_truncate_then_read() {
|
|
return test_file_framework(__test_truncate_then_read);
|
|
}
|
|
|
|
static int test_truncate_then_write() {
|
|
return test_file_framework(__test_truncate_then_write);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test suite main
|
|
// ============================================================================
|
|
|
|
static test_case_t test_cases[] = {
|
|
TEST_CASE(test_truncate),
|
|
TEST_CASE(test_open_truncate_existing_file),
|
|
TEST_CASE(test_truncate_then_write),
|
|
TEST_CASE(test_truncate_then_read),
|
|
};
|
|
|
|
int main(int argc, const char *argv[]) {
|
|
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
|
|
}
|