occlum/test/rename/main.c
2022-08-15 09:21:52 +08:00

243 lines
7.0 KiB
C

#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include "test_fs.h"
// ============================================================================
// Helper function
// ============================================================================
#define WRITE_MSG "Hello World"
static int create_file_with_content(const char *file_path, const char *msg) {
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");
}
if (msg != NULL) {
if (write(fd, msg, strlen(msg)) <= 0) {
THROW_ERROR("failed to write to the file");
}
}
close(fd);
return 0;
}
// ============================================================================
// Test cases for rename
// ============================================================================
static int __test_rename(const char *old_path, const char *new_path) {
struct stat stat_buf;
int ret;
if (rename(old_path, new_path) < 0) {
THROW_ERROR("failed to rename file");
}
if (fs_check_file_content(new_path, WRITE_MSG) < 0) {
THROW_ERROR("failed to check file content");
}
ret = stat(old_path, &stat_buf);
if (!(ret < 0 && errno == ENOENT)) {
THROW_ERROR("stat on old path should return ENOENT");
}
if (unlink(new_path) < 0) {
THROW_ERROR("failed to remove the new file");
}
return 0;
}
static int __test_renameat(const char *old_path, const char *new_path) {
struct stat stat_buf;
char old_dir_buf[PATH_MAX] = { 0 };
char old_base_buf[PATH_MAX] = { 0 };
char new_dir_buf[PATH_MAX] = { 0 };
char new_base_buf[PATH_MAX] = { 0 };
char *old_dir_name, *old_file_name, *new_dir_name, *new_file_name;
int old_dirfd, new_dirfd, ret;
if (fs_split_path(old_path, old_dir_buf, &old_dir_name, old_base_buf,
&old_file_name) < 0) {
THROW_ERROR("failed to split old path");
}
old_dirfd = open(old_dir_name, O_RDONLY);
if (old_dirfd < 0) {
THROW_ERROR("failed to open old dir");
}
if (fs_split_path(new_path, new_dir_buf, &new_dir_name, new_base_buf,
&new_file_name) < 0) {
THROW_ERROR("failed to split new path");
}
new_dirfd = open(new_dir_name, O_RDONLY);
if (new_dirfd < 0) {
THROW_ERROR("failed to open new dir");
}
if (renameat(old_dirfd, old_file_name, new_dirfd, new_file_name) < 0) {
THROW_ERROR("failed to rename with dirfd");
}
close(old_dirfd);
close(new_dirfd);
if (fs_check_file_content(new_path, WRITE_MSG) < 0) {
THROW_ERROR("failed to check file content");
}
ret = stat(old_path, &stat_buf);
if (!(ret < 0 && errno == ENOENT)) {
THROW_ERROR("stat on old path should return ENOENT");
}
if (unlink(new_path) < 0) {
THROW_ERROR("failed to remove the new file");
}
return 0;
}
typedef int(*test_rename_func_t)(const char *, const char *);
static int test_rename_framework(test_rename_func_t fn, bool target_exist) {
const char *old_path = "/root/test_filesystem_rename_old.txt";
const char *new_path = "/root/test_filesystem_rename_new.txt";
if (create_file_with_content(old_path, WRITE_MSG) < 0) {
THROW_ERROR("failed to create old file with content");
}
if (target_exist) {
if (create_file_with_content(new_path, NULL) < 0) {
THROW_ERROR("failed to create new file");
}
}
if (fn(old_path, new_path) < 0) {
return -1;
}
return 0;
}
static int test_rename() {
return test_rename_framework(__test_rename, false);
}
static int test_rename_with_target_exist() {
return test_rename_framework(__test_rename, true);
}
static int test_renameat() {
return test_rename_framework(__test_renameat, false);
}
static int test_rename_dir() {
const char *old_dir = "/root/test_old_dir/";
const char *new_dir = "/root/test_new_dir";
const char *file_name = "test_file.txt";
char file_buf[128] = { 0 };
mode_t mode = 00775;
struct stat stat_buf;
int ret;
if (mkdir(old_dir, mode) < 0) {
THROW_ERROR("failed to mkdir old dir");
}
ret = snprintf(file_buf, sizeof(file_buf), "%s/%s", old_dir, file_name);
if (ret >= sizeof(file_buf) || ret < 0) {
THROW_ERROR("failed to copy file buf");
}
if (create_file_with_content(file_buf, WRITE_MSG) < 0) {
THROW_ERROR("failed to create file in old dir");
}
if (rename(old_dir, new_dir) < 0) {
THROW_ERROR("failed to rename dir");
}
ret = snprintf(file_buf, sizeof(file_buf), "%s/%s", new_dir, file_name);
if (ret >= sizeof(file_buf) || ret < 0) {
THROW_ERROR("failed to copy file buf");
}
if (fs_check_file_content(file_buf, WRITE_MSG) < 0) {
THROW_ERROR("failed to check file content");
}
ret = stat(old_dir, &stat_buf);
if (!(ret < 0 && errno == ENOENT)) {
THROW_ERROR("stat on old dir should return ENOENT");
}
if (unlink(file_buf) < 0) {
THROW_ERROR("failed to remove the file in new dir");
}
if (rmdir(new_dir) < 0) {
THROW_ERROR("failed to remove the new dir");
}
return 0;
}
static int test_rename_dir_to_subdir() {
const char *old_dir = "/root/test_old_dir";
mode_t mode = 00775;
int ret;
char sub_dir[PATH_MAX] = { 0 };
ret = snprintf(sub_dir, sizeof(sub_dir), "%s/test_new_dir", old_dir);
if (ret >= sizeof(sub_dir) || ret < 0) {
THROW_ERROR("failed to init new dir path");
}
if (mkdir(old_dir, mode) < 0) {
THROW_ERROR("failed to mkdir");
}
ret = rename(old_dir, sub_dir);
if (ret == 0 || errno != EINVAL) {
THROW_ERROR("failed to check rename dir to subdir");
}
if (rmdir(old_dir) < 0) {
THROW_ERROR("failed to rmdir");
}
return 0;
}
static int test_rename_file_as_dir() {
const char *old_file = "/root/test_old_file";
const char *old_dir = "/root/test_old_file/";
const char *new_dir = "/root/test_new_dir";
if (create_file_with_content(old_file, WRITE_MSG) < 0) {
THROW_ERROR("failed to create old file with content");
}
int ret = rename(old_dir, new_dir);
if (ret == 0 || errno != ENOTDIR) {
THROW_ERROR("failed to check rename file as dir");
}
if (unlink(old_file) < 0) {
THROW_ERROR("failed to remove file");
}
return 0;
}
// ============================================================================
// Test suite main
// ============================================================================
static test_case_t test_cases[] = {
// TODO: test more corner cases
TEST_CASE(test_rename),
TEST_CASE(test_rename_with_target_exist),
TEST_CASE(test_renameat),
TEST_CASE(test_rename_dir),
TEST_CASE(test_rename_dir_to_subdir),
TEST_CASE(test_rename_file_as_dir),
};
int main(int argc, const char *argv[]) {
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
}