diff --git a/CHANGELOG.md b/CHANGELOG.md index 12ec77526cc57f0f042d74aeef17bd971454e1ce..1db35e7339e9f4540f0cc955e28246c953615236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Additional tests to increase code coverage ([!141](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/141)). - GKFS_ENABLE_UNUSED_FUNCTIONS added to disable code to increase code coverage. - Updated Parallax version to new API (parallax option needs kv_format.parallax in the path, and the database in a device with O_DIRECT) +- Support for increasing file size via `truncate()` added ([!159](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/159) ### Changed diff --git a/src/client/gkfs_functions.cpp b/src/client/gkfs_functions.cpp index 23db5e0f0a055530bcff78b607e12a5b6662f74f..95a09f1c105224c4f288fbf116c2995522bf90e4 100644 --- a/src/client/gkfs_functions.cpp +++ b/src/client/gkfs_functions.cpp @@ -143,6 +143,7 @@ gkfs_open(const std::string& path, mode_t mode, int flags) { errno = ENOTSUP; return -1; } + // metadata object filled during create or stat gkfs::metadata::Metadata md{}; if(flags & O_CREAT) { @@ -578,9 +579,27 @@ gkfs_truncate(const std::string& path, off_t length) { auto size = md->size(); if(static_cast(length) > size) { - LOG(DEBUG, "Length is greater then file size: {} > {}", length, size); - errno = EINVAL; - return -1; + LOG(DEBUG, "Length is greater then file size: '{}' > '{}'", length, + size); + auto output_fd = gkfs_open(path, md->mode(), O_WRONLY); + if(output_fd == -1) { + errno = EINVAL; + return -1; + } + gkfs_lseek(output_fd, 0, SEEK_END); + ssize_t n = static_cast(length) - size; + // Zeroes the buffer. All make_* are value initialized + auto buf = std::make_unique(n); + if(!buf) { + errno = ENOMEM; + return -1; + } + if(gkfs_write(output_fd, buf.get(), (size_t) n) != n) { + errno = EINVAL; + return -1; + } + CTX->file_map()->remove(output_fd); + return 0; } return gkfs_truncate(path, size, length); } @@ -677,8 +696,10 @@ ssize_t gkfs_write(int fd, const void* buf, size_t count) { auto gkfs_fd = CTX->file_map()->get(fd); auto pos = gkfs_fd->pos(); // retrieve the current offset - if(gkfs_fd->get_flag(gkfs::filemap::OpenFile_flags::append)) + if(gkfs_fd->get_flag(gkfs::filemap::OpenFile_flags::append)) { gkfs_lseek(gkfs_fd, 0, SEEK_END); + pos = gkfs_fd->pos(); // Pos should be updated with append + } auto ret = gkfs_pwrite(gkfs_fd, reinterpret_cast(buf), count, pos); // Update offset in file descriptor in the file map diff --git a/tests/integration/data/test_truncate.py b/tests/integration/data/test_truncate.py index 4d6fc40da3d758defd848bce889f46a33f9809dd..b1321dfdce127ede0931588766635ff8c932644a 100644 --- a/tests/integration/data/test_truncate.py +++ b/tests/integration/data/test_truncate.py @@ -150,7 +150,11 @@ def test_fail_truncate(gkfs_daemon, gkfs_client): # Truncate to a size greater than the file size ret = gkfs_client.truncate(truncfile, buf_length + 1) - assert ret.retval == -1 - assert ret.errno == errno.EINVAL + assert ret.retval == 0 + + + # Size should increase + ret = gkfs_client.stat(truncfile) + assert ret.statbuf.st_size == buf_length+1