Skip to content

Commit

Permalink
Fix a bug in file truncation. (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
rmind authored Mar 6, 2021
1 parent 65f770f commit c8f311d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
7 changes: 5 additions & 2 deletions src/core/fileobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,10 @@ fileobj_getsize(fileobj_t *fobj)
int
fileobj_setsize(fileobj_t *fobj, size_t len)
{
if (fileobj_dataload(fobj) == -1) {
/*
* Only load the data if truncating to non-zero.
*/
if (len && fileobj_dataload(fobj) == -1) {
app_elog(LOG_DEBUG, "%s: fileobj_dataload() failed", __func__);
errno = EIO;
return -1;
Expand All @@ -415,7 +418,7 @@ fileobj_setsize(fileobj_t *fobj, size_t len)
* Note: if new length is zero, then sbuffer_move() will free the
* old buffer and will return NULL.
*/
if (len && sbuffer_move(&fobj->sbuf, len, 0) == NULL) {
if (sbuffer_move(&fobj->sbuf, len, 0) == NULL && len) {
app_elog(LOG_DEBUG, "%s: sbuffer_move() failed", __func__);
return -1;
}
Expand Down
5 changes: 4 additions & 1 deletion src/core/storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ storage_map_obj(rvault_t *vault, int fd, size_t file_len)
return NULL;
}
if ((hdr = safe_mmap(file_len, fd, 0)) == NULL) {
app_elog(LOG_DEBUG, "%s: mmap() failed", __func__);
return NULL;
}
aetag_len = crypto_get_aetaglen(vault->crypto);
Expand Down Expand Up @@ -325,8 +326,10 @@ storage_read_data(rvault_t *vault, int fd, size_t file_len, sbuffer_t *sbuf)
if (FILEOBJ_EDATA_LEN(hdr) == 0) {
/*
* Note: it is currently an error to have no encrypted data.
* Empty file is represented as an empty file.
* Empty file is represented as a fully empty file without
* the header.
*/
app_elog(LOG_DEBUG, "%s: edata length is zero", __func__);
goto out;
}
memset(&tmpsbuf, 0, sizeof(sbuffer_t));
Expand Down
8 changes: 7 additions & 1 deletion src/fuse/rvaultfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,13 @@ rvaultfs_truncate(const char *path, off_t size)
if (size < 0) {
return -EINVAL;
}
if ((fobj = fileobj_open(vault, path, O_WRONLY, FOBJ_OMASK)) == NULL) {

/*
* Note: use O_RDWR instead of O_WRONLY, since the data might have
* to be loaded before truncation (e.g. in order decompress and
* determine the correct offset).
*/
if ((fobj = fileobj_open(vault, path, O_RDWR, FOBJ_OMASK)) == NULL) {
return -errno;
}
if (fileobj_setsize(fobj, (size_t)size) == -1) {
Expand Down
39 changes: 37 additions & 2 deletions src/tests/t_fileobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@
#define TEST_BLOCK_COUNT 128
#define TEST_BLOCK_SIZE (32U * 1024) // 32 KB

static void
test_file_basic(rvault_t *vault)
{
fileobj_t *fobj;
ssize_t nbytes;

fobj = fileobj_open(vault, "/basic", O_CREAT | O_RDWR, FOBJ_OMASK);
assert(fobj != NULL);
fileobj_close(fobj);

fobj = fileobj_open(vault, "/basic", O_RDONLY, FOBJ_OMASK);
assert(fobj != NULL);
nbytes = fileobj_getsize(fobj);
assert(nbytes == 0);
fileobj_close(fobj);
}

static void
test_file_expand(rvault_t *vault)
{
Expand Down Expand Up @@ -118,7 +135,7 @@ test_file_onebyte(rvault_t *vault)
}

static void
test_file_zero(rvault_t *vault)
test_file_setsize(rvault_t *vault)
{
static const unsigned zeros[16];
unsigned buf[16];
Expand Down Expand Up @@ -150,16 +167,34 @@ test_file_zero(rvault_t *vault)
nbytes = fileobj_pread(fobj, buf, sizeof(buf), 0);
assert(nbytes == 0);
fileobj_close(fobj);

/*
* Write some data, shrink size, expand, check.
*/
fobj = fileobj_open(vault, "/empty", O_CREAT | O_RDWR, FOBJ_OMASK);
assert(fobj != NULL);

nbytes = fileobj_pwrite(fobj, (const void *)"ab", 2, 0);
assert(nbytes == 2);

fileobj_setsize(fobj, 1);
fileobj_setsize(fobj, 3);

nbytes = fileobj_pread(fobj, buf, sizeof(buf), 0);
assert(nbytes == 3);
assert(memcmp(buf, "a\0\0", 3) == 0);
fileobj_close(fobj);
}

static void
run_tests(const char *cipher)
{
char *base_path = NULL;
rvault_t *vault = mock_get_vault(cipher, &base_path);
test_file_basic(vault);
test_file_expand(vault);
test_file_onebyte(vault);
test_file_zero(vault);
test_file_setsize(vault);
mock_cleanup_vault(vault, base_path);
}

Expand Down

0 comments on commit c8f311d

Please sign in to comment.