diff --git a/.gitignore b/.gitignore index 5093f2e..d656a77 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ config.status config.sub configure configure.scan +configure.ac~ depcomp install-sh libtool @@ -86,6 +87,7 @@ test/junk_data test/s3proxy-* test/write_multiblock test/mknod_test +test/truncate_read_file # # Windows ports diff --git a/src/fdcache_page.cpp b/src/fdcache_page.cpp index ffc79b9..4eeff19 100644 --- a/src/fdcache_page.cpp +++ b/src/fdcache_page.cpp @@ -456,7 +456,13 @@ bool PageList::Resize(off_t size, bool is_loaded, bool is_modified) off_t total = Size(); if(0 == total){ + // [NOTE] + // The is_shrink flag remains unchanged in this function. + // + bool backup_is_shrink = is_shrink; + Init(size, is_loaded, is_modified); + is_shrink = backup_is_shrink; }else if(total < size){ // add new area diff --git a/src/metaheader.cpp b/src/metaheader.cpp index fc6f630..571dd6e 100644 --- a/src/metaheader.cpp +++ b/src/metaheader.cpp @@ -245,7 +245,7 @@ gid_t get_gid(const headers_t& meta) blkcnt_t get_blocks(off_t size) { - return size / 512 + 1; + return (size / 512) + (0 == (size % 512) ? 0 : 1); } time_t cvtIAMExpireStringToTime(const char* s) diff --git a/src/s3fs.cpp b/src/s3fs.cpp index 3d3eeae..bc7cb4c 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -2682,19 +2682,32 @@ static int s3fs_open(const char* _path, struct fuse_file_info* fi) return result; } + AutoFdEntity autoent; + FdEntity* ent; + headers_t meta; + if((unsigned int)fi->flags & O_TRUNC){ if(0 != st.st_size){ st.st_size = 0; needs_flush = true; } + }else{ + // [NOTE] + // If the file has already been opened and edited, the file size in + // the edited state is given priority. + // This prevents the file size from being reset to its original size + // if you keep the file open, shrink its size, and then read the file + // from another process while it has not yet been flushed. + // + if(NULL != (ent = autoent.OpenExistFdEntity(path)) && ent->IsModified()){ + // sets the file size being edited. + ent->GetSize(st.st_size); + } } if(!S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)){ st.st_mtime = -1; } - AutoFdEntity autoent; - FdEntity* ent; - headers_t meta; if(0 != (result = get_object_attribute(path, NULL, &meta, true, NULL, true))){ // no truncate cache return result; } diff --git a/test/Makefile.am b/test/Makefile.am index a57a18f..808c059 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -32,11 +32,13 @@ testdir = test noinst_PROGRAMS = \ junk_data \ write_multiblock \ - mknod_test + mknod_test \ + truncate_read_file -junk_data_SOURCES = junk_data.c -write_multiblock_SOURCES = write_multiblock.cc -mknod_test_SOURCES = mknod_test.c +junk_data_SOURCES = junk_data.c +write_multiblock_SOURCES = write_multiblock.cc +mknod_test_SOURCES = mknod_test.c +truncate_read_file_SOURCES = truncate_read_file.c # # Local variables: diff --git a/test/integration-test-main.sh b/test/integration-test-main.sh index 9f01fdc..ee6adc8 100755 --- a/test/integration-test-main.sh +++ b/test/integration-test-main.sh @@ -112,6 +112,28 @@ function test_truncate_shrink_file { rm_test_file "${BIG_TRUNCATE_TEST_FILE}" } +function test_truncate_shrink_read_file { + describe "Testing truncate(shrink) and read file ..." + + # Initiate file size is 1024, and shrink file size is 512 + local init_size=1024 + local shrink_size=512 + + # create file + dd if=/dev/urandom of="${TEST_TEXT_FILE}" bs="${init_size}" count=1 + + # truncate(shrink) file and read it before flusing + ../../truncate_read_file "${TEST_TEXT_FILE}" "${shrink_size}" + + # check file size + check_file_size "${TEST_TEXT_FILE}" "${shrink_size}" + + # Truncate the file to 1024 length + local t_size=1024 + + rm_test_file +} + function test_mv_file { describe "Testing mv file function ..." # if the rename file exists, delete it @@ -2610,6 +2632,7 @@ function add_all_tests { add_tests test_truncate_upload add_tests test_truncate_empty_file add_tests test_truncate_shrink_file + add_tests test_truncate_shrink_read_file add_tests test_mv_file add_tests test_mv_to_exist_file add_tests test_mv_empty_directory diff --git a/test/truncate_read_file.c b/test/truncate_read_file.c new file mode 100644 index 0000000..2959439 --- /dev/null +++ b/test/truncate_read_file.c @@ -0,0 +1,81 @@ +/* + * s3fs - FUSE-based file system backed by Amazon S3 + * + * Copyright(C) 2021 Andrew Gaul + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +// [NOTE] +// This is a program used for file size inspection. +// File size checking should be done by the caller of this program. +// This program truncates the file and reads the file in another process +// between truncate and flush(close file). +// +int main(int argc, char *argv[]) +{ + if(argc != 3){ + fprintf(stderr, "[ERROR] Wrong paraemters\n"); + fprintf(stdout, "[Usage] truncate_read_file \n"); + exit(EXIT_FAILURE); + } + + const char* filepath = argv[1]; + off_t size = (off_t)strtoull(argv[2], NULL, 10); + int fd; + + // open file + if(-1 == (fd = open(filepath, O_RDWR))){ + fprintf(stderr, "[ERROR] Could not open file(%s)\n", filepath); + exit(EXIT_FAILURE); + } + + // truncate + if(0 != ftruncate(fd, size)){ + fprintf(stderr, "[ERROR] Could not truncate file(%s) to %lld byte.\n", filepath, (long long)size); + close(fd); + exit(EXIT_FAILURE); + } + + // run sub-process for reading file(cat) + char szCommand[1024]; + sprintf(szCommand, "cat %s >/dev/null 2>&1", filepath); + if(0 != system(szCommand)){ + fprintf(stderr, "[ERROR] Failed to run sub-process(cat).\n"); + close(fd); + exit(EXIT_FAILURE); + } + + // close file(flush) + close(fd); + + exit(EXIT_SUCCESS); +} + +/* +* Local variables: +* tab-width: 4 +* c-basic-offset: 4 +* End: +* vim600: expandtab sw=4 ts=4 fdm=marker +* vim<600: expandtab sw=4 ts=4 +*/