Store and retrieve file change time

This introduces a new header with the change time; existing objects
will report modification time.  Fixes #771.
This commit is contained in:
Andrew Gaul 2019-01-06 17:51:42 -08:00
parent b68d97c6bf
commit 2c43b1e12b
8 changed files with 118 additions and 12 deletions

View File

@ -620,6 +620,9 @@ bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst,
// mtime // mtime
pst->st_mtime = get_mtime(meta); pst->st_mtime = get_mtime(meta);
// ctime
pst->st_ctime = get_ctime(meta);
// size // size
pst->st_size = get_size(meta); pst->st_size = get_size(meta);

View File

@ -1050,11 +1050,23 @@ int FdEntity::SetMtime(time_t time)
return -errno; return -errno;
} }
} }
orgmeta["x-amz-meta-ctime"] = str(time);
orgmeta["x-amz-meta-mtime"] = str(time); orgmeta["x-amz-meta-mtime"] = str(time);
return 0; return 0;
} }
bool FdEntity::UpdateCtime(void)
{
AutoLock auto_lock(&fdent_lock);
struct stat st;
if(!GetStats(st)){
return false;
}
orgmeta["x-amz-meta-ctime"] = str(st.st_ctime);
return true;
}
bool FdEntity::UpdateMtime(void) bool FdEntity::UpdateMtime(void)
{ {
AutoLock auto_lock(&fdent_lock); AutoLock auto_lock(&fdent_lock);
@ -1062,6 +1074,7 @@ bool FdEntity::UpdateMtime(void)
if(!GetStats(st)){ if(!GetStats(st)){
return false; return false;
} }
orgmeta["x-amz-meta-ctime"] = str(st.st_ctime);
orgmeta["x-amz-meta-mtime"] = str(st.st_mtime); orgmeta["x-amz-meta-mtime"] = str(st.st_mtime);
return true; return true;
} }

View File

@ -155,6 +155,7 @@ class FdEntity
bool GetStats(struct stat& st); bool GetStats(struct stat& st);
int SetMtime(time_t time); int SetMtime(time_t time);
bool UpdateCtime(void);
bool UpdateMtime(void); bool UpdateMtime(void);
bool GetSize(size_t& size); bool GetSize(size_t& size);
bool SetMode(mode_t mode); bool SetMode(mode_t mode);

View File

@ -963,12 +963,14 @@ static int create_file_object(const char* path, mode_t mode, uid_t uid, gid_t gi
{ {
S3FS_PRN_INFO2("[path=%s][mode=%04o]", path, mode); S3FS_PRN_INFO2("[path=%s][mode=%04o]", path, mode);
time_t now = time(NULL);
headers_t meta; headers_t meta;
meta["Content-Type"] = S3fsCurl::LookupMimeType(string(path)); meta["Content-Type"] = S3fsCurl::LookupMimeType(string(path));
meta["x-amz-meta-uid"] = str(uid); meta["x-amz-meta-uid"] = str(uid);
meta["x-amz-meta-gid"] = str(gid); meta["x-amz-meta-gid"] = str(gid);
meta["x-amz-meta-mode"] = str(mode); meta["x-amz-meta-mode"] = str(mode);
meta["x-amz-meta-mtime"] = str(time(NULL)); meta["x-amz-meta-ctime"] = str(now);
meta["x-amz-meta-mtime"] = str(now);
S3fsCurl s3fscurl(true); S3fsCurl s3fscurl(true);
return s3fscurl.PutRequest(path, meta, -1); // fd=-1 means for creating zero byte object. return s3fscurl.PutRequest(path, meta, -1); // fd=-1 means for creating zero byte object.
@ -1055,6 +1057,7 @@ static int create_directory_object(const char* path, mode_t mode, time_t time, u
meta["x-amz-meta-uid"] = str(uid); meta["x-amz-meta-uid"] = str(uid);
meta["x-amz-meta-gid"] = str(gid); meta["x-amz-meta-gid"] = str(gid);
meta["x-amz-meta-mode"] = str(mode); meta["x-amz-meta-mode"] = str(mode);
meta["x-amz-meta-ctime"] = str(time);
meta["x-amz-meta-mtime"] = str(time); meta["x-amz-meta-mtime"] = str(time);
S3fsCurl s3fscurl; S3fsCurl s3fscurl;
@ -1199,10 +1202,12 @@ static int s3fs_symlink(const char* from, const char* to)
return result; return result;
} }
time_t now = time(NULL);
headers_t headers; headers_t headers;
headers["Content-Type"] = string("application/octet-stream"); // Static headers["Content-Type"] = string("application/octet-stream"); // Static
headers["x-amz-meta-mode"] = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); headers["x-amz-meta-mode"] = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
headers["x-amz-meta-mtime"] = str(time(NULL)); headers["x-amz-meta-ctime"] = str(now);
headers["x-amz-meta-mtime"] = str(now);
headers["x-amz-meta-uid"] = str(pcxt->uid); headers["x-amz-meta-uid"] = str(pcxt->uid);
headers["x-amz-meta-gid"] = str(pcxt->gid); headers["x-amz-meta-gid"] = str(pcxt->gid);
@ -1591,6 +1596,7 @@ static int s3fs_chmod(const char* path, mode_t mode)
} }
}else{ }else{
// normal object or directory object of newer version // normal object or directory object of newer version
meta["x-amz-meta-ctime"] = str(time(NULL));
meta["x-amz-meta-mode"] = str(mode); meta["x-amz-meta-mode"] = str(mode);
meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str())); meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str()));
meta["x-amz-metadata-directive"] = "REPLACE"; meta["x-amz-metadata-directive"] = "REPLACE";
@ -1607,6 +1613,7 @@ static int s3fs_chmod(const char* path, mode_t mode)
// //
FdEntity* ent; FdEntity* ent;
if(NULL != (ent = FdManager::get()->ExistOpen(path))){ if(NULL != (ent = FdManager::get()->ExistOpen(path))){
ent->UpdateCtime();
ent->SetMode(mode); // Set new mode to opened fd. ent->SetMode(mode); // Set new mode to opened fd.
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
} }
@ -1747,6 +1754,7 @@ static int s3fs_chown(const char* path, uid_t uid, gid_t gid)
return result; return result;
} }
}else{ }else{
meta["x-amz-meta-ctime"] = str(time(NULL));
meta["x-amz-meta-uid"] = str(uid); meta["x-amz-meta-uid"] = str(uid);
meta["x-amz-meta-gid"] = str(gid); meta["x-amz-meta-gid"] = str(gid);
meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str())); meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str()));
@ -2032,9 +2040,11 @@ static int s3fs_truncate(const char* path, off_t size)
if(NULL == (pcxt = fuse_get_context())){ if(NULL == (pcxt = fuse_get_context())){
return -EIO; return -EIO;
} }
time_t now = time(NULL);
meta["Content-Type"] = string("application/octet-stream"); // Static meta["Content-Type"] = string("application/octet-stream"); // Static
meta["x-amz-meta-mode"] = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); meta["x-amz-meta-mode"] = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
meta["x-amz-meta-mtime"] = str(time(NULL)); meta["x-amz-meta-ctime"] = str(now);
meta["x-amz-meta-mtime"] = str(now);
meta["x-amz-meta-uid"] = str(pcxt->uid); meta["x-amz-meta-uid"] = str(pcxt->uid);
meta["x-amz-meta-gid"] = str(pcxt->gid); meta["x-amz-meta-gid"] = str(pcxt->gid);
@ -3103,6 +3113,7 @@ static int s3fs_setxattr(const char* path, const char* name, const char* value,
} }
// set xattr all object // set xattr all object
meta["x-amz-meta-ctime"] = str(time(NULL));
meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str())); meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str()));
meta["x-amz-metadata-directive"] = "REPLACE"; meta["x-amz-metadata-directive"] = "REPLACE";

View File

@ -753,10 +753,10 @@ time_t get_mtime(const char *s)
return static_cast<time_t>(s3fs_strtoofft(s)); return static_cast<time_t>(s3fs_strtoofft(s));
} }
time_t get_mtime(headers_t& meta, bool overcheck) static time_t get_time(headers_t& meta, bool overcheck, const char *header)
{ {
headers_t::const_iterator iter; headers_t::const_iterator iter;
if(meta.end() == (iter = meta.find("x-amz-meta-mtime"))){ if(meta.end() == (iter = meta.find(header))){
if(overcheck){ if(overcheck){
return get_lastmodified(meta); return get_lastmodified(meta);
} }
@ -765,6 +765,16 @@ time_t get_mtime(headers_t& meta, bool overcheck)
return get_mtime((*iter).second.c_str()); return get_mtime((*iter).second.c_str());
} }
time_t get_mtime(headers_t& meta, bool overcheck)
{
return get_time(meta, overcheck, "x-amz-meta-mtime");
}
time_t get_ctime(headers_t& meta, bool overcheck)
{
return get_time(meta, overcheck, "x-amz-meta-ctime");
}
off_t get_size(const char *s) off_t get_size(const char *s)
{ {
return s3fs_strtoofft(s); return s3fs_strtoofft(s);

View File

@ -119,6 +119,7 @@ bool delete_files_in_dir(const char* dir, bool is_remove_own);
time_t get_mtime(const char *s); time_t get_mtime(const char *s);
time_t get_mtime(headers_t& meta, bool overcheck = true); time_t get_mtime(headers_t& meta, bool overcheck = true);
time_t get_ctime(headers_t& meta, bool overcheck = true);
off_t get_size(const char *s); off_t get_size(const char *s);
off_t get_size(headers_t& meta); off_t get_size(headers_t& meta);
mode_t get_mode(const char *s); mode_t get_mode(const char *s);

View File

@ -400,13 +400,8 @@ function test_mtime_file {
#copy the test file with preserve mode #copy the test file with preserve mode
cp -p $TEST_TEXT_FILE $ALT_TEST_TEXT_FILE cp -p $TEST_TEXT_FILE $ALT_TEST_TEXT_FILE
if [ `uname` = "Darwin" ]; then testmtime=`get_mtime $TEST_TEXT_FILE`
testmtime=`stat -f "%m" $TEST_TEXT_FILE` altmtime=`get_mtime $ALT_TEST_TEXT_FILE`
altmtime=`stat -f "%m" $ALT_TEST_TEXT_FILE`
else
testmtime=`stat -c %Y $TEST_TEXT_FILE`
altmtime=`stat -c %Y $ALT_TEST_TEXT_FILE`
fi
if [ "$testmtime" -ne "$altmtime" ] if [ "$testmtime" -ne "$altmtime" ]
then then
echo "File times do not match: $testmtime != $altmtime" echo "File times do not match: $testmtime != $altmtime"
@ -414,6 +409,61 @@ function test_mtime_file {
fi fi
} }
function test_update_time() {
describe "Testing update time function ..."
# create the test
mk_test_file
mtime=`get_ctime $TEST_TEXT_FILE`
ctime=`get_mtime $TEST_TEXT_FILE`
sleep 2
chmod +x $TEST_TEXT_FILE
ctime2=`get_ctime $TEST_TEXT_FILE`
mtime2=`get_mtime $TEST_TEXT_FILE`
if [ $ctime -eq $ctime2 -o $mtime -ne $mtime2 ]; then
echo "Expected updated ctime: $ctime != $ctime2 and same mtime: $mtime == $mtime2"
return 1
fi
sleep 2
chown $UID:$UID $TEST_TEXT_FILE;
ctime3=`get_ctime $TEST_TEXT_FILE`
mtime3=`get_mtime $TEST_TEXT_FILE`
if [ $ctime2 -eq $ctime3 -o $mtime2 -ne $mtime3 ]; then
echo "Expected updated ctime: $ctime2 != $ctime3 and same mtime: $mtime2 == $mtime3"
return 1
fi
if command -v setfattr >/dev/null 2>&1; then
sleep 2
setfattr -n key -v value $TEST_TEXT_FILE
ctime4=`get_ctime $TEST_TEXT_FILE`
mtime4=`get_mtime $TEST_TEXT_FILE`
if [ $ctime3 -eq $ctime4 -o $mtime3 -ne $mtime4 ]; then
echo "Expected updated ctime: $ctime3 != $ctime4 and same mtime: $mtime3 == $mtime4"
return 1
fi
else
echo "Skipping extended attribute test"
ctime4=`get_ctime $TEST_TEXT_FILE`
mtime4=`get_mtime $TEST_TEXT_FILE`
fi
sleep 2
echo foo >> $TEST_TEXT_FILE
ctime5=`get_ctime $TEST_TEXT_FILE`
mtime5=`get_mtime $TEST_TEXT_FILE`
if [ $ctime4 -eq $ctime5 -o $mtime4 -eq $mtime5 ]; then
echo "Expected updated ctime: $ctime4 != $ctime5 and updated mtime: $mtime4 != $mtime5"
return 1
fi
}
function test_rm_rf_dir { function test_rm_rf_dir {
describe "Test that rm -rf will remove directory with contents" describe "Test that rm -rf will remove directory with contents"
# Create a dir with some files and directories # Create a dir with some files and directories
@ -458,6 +508,7 @@ function add_all_tests {
add_tests test_symlink add_tests test_symlink
add_tests test_extended_attributes add_tests test_extended_attributes
add_tests test_mtime_file add_tests test_mtime_file
add_tests test_update_time
add_tests test_rm_rf_dir add_tests test_rm_rf_dir
add_tests test_write_after_seek_ahead add_tests test_write_after_seek_ahead
} }

View File

@ -169,3 +169,19 @@ function run_suite {
return 0 return 0
fi fi
} }
function get_ctime() {
if [ `uname` = "Darwin" ]; then
stat -f "%c" "$1"
else
stat -c %Z "$1"
fi
}
function get_mtime() {
if [ `uname` = "Darwin" ]; then
stat -f "%m" "$1"
else
stat -c %Y "$1"
fi
}