Add O_TRUNC support in open syscall and rewrite the truncate test
This commit is contained in:
parent
001df6f309
commit
eb046d4241
@ -84,6 +84,10 @@ impl CreationFlags {
|
|||||||
}
|
}
|
||||||
self.contains(CreationFlags::O_DIRECTORY)
|
self.contains(CreationFlags::O_DIRECTORY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn should_truncate(&self) -> bool {
|
||||||
|
self.contains(CreationFlags::O_TRUNC)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -128,7 +128,9 @@ impl INode for HNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resize(&self, len: usize) -> Result<()> {
|
fn resize(&self, len: usize) -> Result<()> {
|
||||||
warn!("HostFS: resize() is unimplemented");
|
let mut guard = self.open_file()?;
|
||||||
|
let file = guard.as_mut().unwrap();
|
||||||
|
try_std!(file.set_len(len as u64));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,6 +243,14 @@ impl INodeFile {
|
|||||||
if access_mode.writable() && inode.metadata()?.type_ == FileType::Dir {
|
if access_mode.writable() && inode.metadata()?.type_ == FileType::Dir {
|
||||||
return_errno!(EISDIR, "Directory cannot be open to write");
|
return_errno!(EISDIR, "Directory cannot be open to write");
|
||||||
}
|
}
|
||||||
|
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
||||||
|
if creation_flags.should_truncate()
|
||||||
|
&& inode.metadata()?.type_ == FileType::File
|
||||||
|
&& access_mode.writable()
|
||||||
|
{
|
||||||
|
// truncate the length to 0
|
||||||
|
inode.resize(0)?;
|
||||||
|
}
|
||||||
let status_flags = StatusFlags::from_bits_truncate(flags);
|
let status_flags = StatusFlags::from_bits_truncate(flags);
|
||||||
Ok(INodeFile {
|
Ok(INodeFile {
|
||||||
inode,
|
inode,
|
||||||
|
@ -246,11 +246,11 @@ impl File for LockedFile {
|
|||||||
let file_size = file.seek(SeekFrom::End(0))? as usize;
|
let file_size = file.seek(SeekFrom::End(0))? as usize;
|
||||||
if file_size < offset {
|
if file_size < offset {
|
||||||
static ZEROS: [u8; 0x1000] = [0; 0x1000];
|
static ZEROS: [u8; 0x1000] = [0; 0x1000];
|
||||||
let mut rest_len = offset - file_size;
|
let mut remaining_len = offset - file_size;
|
||||||
while rest_len != 0 {
|
while remaining_len != 0 {
|
||||||
let l = rest_len.min(0x1000);
|
let l = remaining_len.min(0x1000);
|
||||||
let len = file.write(&ZEROS[..l])?;
|
let len = file.write(&ZEROS[..l])?;
|
||||||
rest_len -= len;
|
remaining_len -= len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,8 +262,31 @@ impl File for LockedFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_len(&self, len: usize) -> DevResult<()> {
|
fn set_len(&self, len: usize) -> DevResult<()> {
|
||||||
// NOTE: do nothing ??
|
// The set_len() is unsupported for SgxFile, we have to
|
||||||
|
// implement it in a slow way by padding null bytes.
|
||||||
|
convert_result!({
|
||||||
|
let mut file = self.0.lock().unwrap();
|
||||||
|
let file_size = file.seek(SeekFrom::End(0))? as usize;
|
||||||
|
let mut reset_len = if len > file_size {
|
||||||
|
// Expand the file by padding null bytes
|
||||||
|
len - file_size
|
||||||
|
} else {
|
||||||
|
// Shrink the file by setting null bytes between len and file_size
|
||||||
|
file.seek(SeekFrom::Start(len as u64))?;
|
||||||
|
file_size - len
|
||||||
|
};
|
||||||
|
static ZEROS: [u8; 0x1000] = [0; 0x1000];
|
||||||
|
while reset_len != 0 {
|
||||||
|
let l = reset_len.min(0x1000);
|
||||||
|
// Probably there's not enough space on disk, let's panic here
|
||||||
|
let written_len = file.write(&ZEROS[..l]).unwrap_or_else(|e| {
|
||||||
|
error!("failed to set null bytes: {}", e);
|
||||||
|
panic!();
|
||||||
|
});
|
||||||
|
reset_len -= written_len;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&self) -> DevResult<()> {
|
fn flush(&self) -> DevResult<()> {
|
||||||
|
@ -66,7 +66,7 @@ static int do_perm_tests(
|
|||||||
size_t num_files,
|
size_t num_files,
|
||||||
int flags, int do_write,
|
int flags, int do_write,
|
||||||
int *expected_results) {
|
int *expected_results) {
|
||||||
flags |= O_CREAT | O_TRUNC;
|
flags |= O_CREAT;
|
||||||
for (size_t i = 0; i < num_files; i++) {
|
for (size_t i = 0; i < num_files; i++) {
|
||||||
const char *filename = files[i];
|
const char *filename = files[i];
|
||||||
int expected_result = expected_results[i];
|
int expected_result = expected_results[i];
|
||||||
|
@ -154,6 +154,21 @@ static int __test_readdir(const char *file_path) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __test_truncate(const char *file_path) {
|
||||||
|
off_t len = 256;
|
||||||
|
if (truncate(file_path, len) < 0) {
|
||||||
|
THROW_ERROR("failed to call truncate");
|
||||||
|
}
|
||||||
|
struct stat stat_buf;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
typedef int(*test_hostfs_func_t)(const char *);
|
typedef int(*test_hostfs_func_t)(const char *);
|
||||||
|
|
||||||
static int test_hostfs_framework(test_hostfs_func_t fn) {
|
static int test_hostfs_framework(test_hostfs_func_t fn) {
|
||||||
@ -191,6 +206,10 @@ static int test_readdir() {
|
|||||||
return test_hostfs_framework(__test_readdir);
|
return test_hostfs_framework(__test_readdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_truncate() {
|
||||||
|
return test_hostfs_framework(__test_truncate);
|
||||||
|
}
|
||||||
|
|
||||||
static int test_mkdir_then_rmdir() {
|
static int test_mkdir_then_rmdir() {
|
||||||
const char *dir_path = "/host/hostfs_dir";
|
const char *dir_path = "/host/hostfs_dir";
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
@ -221,6 +240,7 @@ static test_case_t test_cases[] = {
|
|||||||
TEST_CASE(test_write_fsync_read),
|
TEST_CASE(test_write_fsync_read),
|
||||||
TEST_CASE(test_rename),
|
TEST_CASE(test_rename),
|
||||||
TEST_CASE(test_readdir),
|
TEST_CASE(test_readdir),
|
||||||
|
TEST_CASE(test_truncate),
|
||||||
TEST_CASE(test_mkdir_then_rmdir),
|
TEST_CASE(test_mkdir_then_rmdir),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,4 +49,14 @@ void close_files(int count, ...) {
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int check_bytes_in_buf(char *buf, size_t len, int expected_byte_val) {
|
||||||
|
for (size_t bi = 0; bi < len; bi++) {
|
||||||
|
if (buf[bi] != (char)expected_byte_val) {
|
||||||
|
THROW_ERROR("check_bytes_in_buf: expect %02X, but found %02X, at offset %lu\n",
|
||||||
|
(unsigned char)expected_byte_val, (unsigned char)buf[bi], bi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __TEST_H */
|
#endif /* __TEST_H */
|
||||||
|
@ -56,4 +56,43 @@ int fs_check_file_content(const char *path, const char *msg) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fill_file_with_repeated_bytes(int fd, size_t len, int byte_val) {
|
||||||
|
char buf[1024 * 4];
|
||||||
|
memset(buf, byte_val, sizeof(buf));
|
||||||
|
|
||||||
|
size_t remain_bytes = len;
|
||||||
|
while (remain_bytes > 0) {
|
||||||
|
int to_write_bytes = MIN(sizeof(buf), remain_bytes);
|
||||||
|
int written_bytes = write(fd, buf, to_write_bytes);
|
||||||
|
if (written_bytes != to_write_bytes) {
|
||||||
|
THROW_ERROR("file write failed");
|
||||||
|
}
|
||||||
|
remain_bytes -= written_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_file_with_repeated_bytes(int fd, size_t len, int expected_byte_val) {
|
||||||
|
size_t remain = len;
|
||||||
|
char read_buf[512];
|
||||||
|
while (remain > 0) {
|
||||||
|
int read_nbytes = read(fd, read_buf, sizeof(read_buf));
|
||||||
|
if (read_nbytes < 0) {
|
||||||
|
// I/O error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
remain -= read_nbytes;
|
||||||
|
if (read_nbytes == 0 && remain > 0) {
|
||||||
|
// Not enough data in the file
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (check_bytes_in_buf(read_buf, read_nbytes, expected_byte_val) < 0) {
|
||||||
|
// Incorrect data
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __TEST_FS_H */
|
#endif /* __TEST_FS_H */
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include "test.h"
|
#include "test_fs.h"
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Helper macros
|
// Helper macros
|
||||||
@ -29,56 +29,6 @@
|
|||||||
// Helper functions
|
// Helper functions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
static int fill_file_with_repeated_bytes(int fd, size_t len, int byte_val) {
|
|
||||||
char buf[PAGE_SIZE];
|
|
||||||
memset(buf, byte_val, sizeof(buf));
|
|
||||||
|
|
||||||
size_t remain_bytes = len;
|
|
||||||
while (remain_bytes > 0) {
|
|
||||||
int to_write_bytes = MIN(sizeof(buf), remain_bytes);
|
|
||||||
int written_bytes = write(fd, buf, to_write_bytes);
|
|
||||||
if (written_bytes != to_write_bytes) {
|
|
||||||
THROW_ERROR("file write failed");
|
|
||||||
}
|
|
||||||
remain_bytes -= written_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int check_bytes_in_buf(char *buf, size_t len, int expected_byte_val) {
|
|
||||||
for (size_t bi = 0; bi < len; bi++) {
|
|
||||||
if (buf[bi] != (char)expected_byte_val) {
|
|
||||||
printf("check_bytes_in_buf: expect %02X, but found %02X, at offset %lu\n",
|
|
||||||
(unsigned char)expected_byte_val, (unsigned char)buf[bi], bi);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int check_file_with_repeated_bytes(int fd, size_t len, int expected_byte_val) {
|
|
||||||
size_t remain = len;
|
|
||||||
char read_buf[512];
|
|
||||||
while (remain > 0) {
|
|
||||||
int read_nbytes = read(fd, read_buf, sizeof(read_buf));
|
|
||||||
if (read_nbytes < 0) {
|
|
||||||
// I/O error
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
remain -= read_nbytes;
|
|
||||||
if (read_nbytes == 0 && remain > 0) {
|
|
||||||
// Not enough data in the file
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (check_bytes_in_buf(read_buf, read_nbytes, expected_byte_val) < 0) {
|
|
||||||
// Incorrect data
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *get_a_stack_ptr() {
|
static void *get_a_stack_ptr() {
|
||||||
volatile int a = 0;
|
volatile int a = 0;
|
||||||
return (void *) &a;
|
return (void *) &a;
|
||||||
|
@ -4,77 +4,232 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "test_fs.h"
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
// ============================================================================
|
||||||
const char *FILE_NAME = "root/test_filesystem_truncate.txt";
|
// Helper function
|
||||||
const int TRUNC_LEN = 256;
|
// ============================================================================
|
||||||
const int TRUNC_LEN1 = 128;
|
|
||||||
const int MODE_MASK = 0777;
|
|
||||||
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
|
static int create_file(const char *file_path) {
|
||||||
|
int fd;
|
||||||
int flags = O_WRONLY | O_CREAT | O_TRUNC;
|
int flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||||
int mode = 00666;
|
int mode = 00666;
|
||||||
int fd = open(FILE_NAME, flags, mode);
|
fd = open(file_path, flags, mode);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
printf("failed to open a file for write\n");
|
THROW_ERROR("failed to create a file");
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (access(FILE_NAME, F_OK) < 0) {
|
|
||||||
printf("cannot access the new file\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ftruncate(fd, TRUNC_LEN);
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("failed to ftruncate the file\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct stat stat_buf;
|
|
||||||
ret = fstat(fd, &stat_buf);
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("failed to fstat the file\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int file_size = stat_buf.st_size;
|
|
||||||
if (file_size != TRUNC_LEN) {
|
|
||||||
printf("Incorrect file size %d. Expected %d\n", file_size, TRUNC_LEN);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int file_mode = stat_buf.st_mode & MODE_MASK;
|
|
||||||
if (file_mode != mode) {
|
|
||||||
printf("Incorrect file mode %o. Expected %o\n", file_mode, mode);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int file_type = stat_buf.st_mode & S_IFMT;
|
|
||||||
if (file_type != S_IFREG) {
|
|
||||||
printf("Incorrect file type %o. Expected %o\n", file_type, S_IFREG);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
ret = truncate(FILE_NAME, TRUNC_LEN1);
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("failed to truncate the file\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = stat(FILE_NAME, &stat_buf);
|
|
||||||
if (ret < 0) {
|
|
||||||
printf("failed to stat the file\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_size = stat_buf.st_size;
|
|
||||||
if (file_size != TRUNC_LEN1) {
|
|
||||||
printf("Incorrect file size %d. Expected %d\n", file_size, TRUNC_LEN1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("(f)truncate, (f)stat test successful\n");
|
|
||||||
return 0;
|
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));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user