Fixed a bug when reading a reduced file without flushing (#2133)

This commit is contained in:
Takeshi Nakatani 2023-03-26 11:45:21 +09:00 committed by GitHub
parent 2cd7c94653
commit a25cb9e07a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 135 additions and 8 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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:

View File

@ -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

81
test/truncate_read_file.c Normal file
View File

@ -0,0 +1,81 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2021 Andrew Gaul <andrew@gaul.org>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
// [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 <file path> <truncate size(bytes)>\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
*/