mirror of
https://github.com/s3fs-fuse/s3fs-fuse.git
synced 2024-12-22 16:58:55 +00:00
Added the function to update mtime/ctime of the parent directory (#2016)
This commit is contained in:
parent
d1388ff446
commit
e715b77307
@ -422,6 +422,10 @@ If the cache is enabled, you can check the integrity of the cache file and the c
|
||||
This option is specified and when sending the SIGUSR1 signal to the s3fs process checks the cache status at that time.
|
||||
This option can take a file path as parameter to output the check result to that file.
|
||||
The file path parameter can be omitted. If omitted, the result will be output to stdout or syslog.
|
||||
.TP
|
||||
\fB\-o\fR update_parent_dir_stat (default is disable)
|
||||
The parent directory's mtime and ctime are updated when a file or directory is created or deleted (when the parent directory's inode is updated).
|
||||
By default, parent directory statistics are not updated.
|
||||
.SS "utility mode options"
|
||||
.TP
|
||||
\fB\-u\fR or \fB\-\-incomplete\-mpu\-list\fR
|
||||
|
@ -149,6 +149,7 @@ class FdEntity
|
||||
bool PunchHole(off_t start = 0, size_t size = 0);
|
||||
|
||||
void MarkDirtyNewFile();
|
||||
bool IsDirtyNewFile() { return (CREATE_FILE_PENDING == pending_status); }
|
||||
|
||||
bool GetLastUpdateUntreatedPart(off_t& start, off_t& size) const;
|
||||
bool ReplaceLastUpdateUntreatedPart(off_t front_start, off_t front_size, off_t behind_start, off_t behind_size);
|
||||
|
192
src/s3fs.cpp
192
src/s3fs.cpp
@ -99,6 +99,7 @@ static off_t max_dirty_data = 5LL * 1024LL * 1024LL * 1024LL;
|
||||
static bool use_wtf8 = false;
|
||||
static off_t fake_diskfree_size = -1; // default is not set(-1)
|
||||
static int max_thread_count = 5; // default is 5
|
||||
static bool update_parent_dir_stat= false; // default not updating parent directory stats
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Global functions : prototype
|
||||
@ -128,6 +129,7 @@ static int rename_object(const char* from, const char* to, bool update_ctime);
|
||||
static int rename_object_nocopy(const char* from, const char* to, bool update_ctime);
|
||||
static int clone_directory_object(const char* from, const char* to, bool update_ctime, const char* pxattrvalue);
|
||||
static int rename_directory(const char* from, const char* to);
|
||||
static int update_mctime_parent_directory(const char* _path);
|
||||
static int remote_mountpath_exists(const char* path);
|
||||
static bool get_meta_xattr_value(const char* path, std::string& rawvalue);
|
||||
static bool get_parent_meta_xattr_value(const char* path, std::string& rawvalue);
|
||||
@ -994,6 +996,13 @@ static int s3fs_mknod(const char *_path, mode_t mode, dev_t rdev)
|
||||
return result;
|
||||
}
|
||||
StatCache::getStatCacheData()->DelStat(path);
|
||||
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(path))){
|
||||
S3FS_PRN_ERR("succeed to mknod the file(%s), but could not update timestamp of its parent directory(result=%d).", path, update_result);
|
||||
}
|
||||
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
return result;
|
||||
@ -1133,6 +1142,13 @@ static int s3fs_mkdir(const char* _path, mode_t mode)
|
||||
result = create_directory_object(path, mode, now, now, now, pcxt->uid, pcxt->gid, pxattrvalue);
|
||||
|
||||
StatCache::getStatCacheData()->DelStat(path);
|
||||
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(path))){
|
||||
S3FS_PRN_ERR("succeed to create the directory(%s), but could not update timestamp of its parent directory(result=%d).", path, update_result);
|
||||
}
|
||||
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
return result;
|
||||
@ -1153,6 +1169,13 @@ static int s3fs_unlink(const char* _path)
|
||||
StatCache::getStatCacheData()->DelStat(path);
|
||||
StatCache::getStatCacheData()->DelSymlink(path);
|
||||
FdManager::DeleteCacheFile(path);
|
||||
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(path))){
|
||||
S3FS_PRN_ERR("succeed to remove the file(%s), but could not update timestamp of its parent directory(result=%d).", path, update_result);
|
||||
}
|
||||
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
return result;
|
||||
@ -1225,6 +1248,13 @@ static int s3fs_rmdir(const char* _path)
|
||||
strpath += "_$folder$";
|
||||
result = s3fscurl.DeleteRequest(strpath.c_str());
|
||||
}
|
||||
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(path))){
|
||||
S3FS_PRN_ERR("succeed to remove the directory(%s), but could not update timestamp of its parent directory(result=%d).", path, update_result);
|
||||
}
|
||||
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
return result;
|
||||
@ -1297,6 +1327,13 @@ static int s3fs_symlink(const char* _from, const char* _to)
|
||||
if(!StatCache::getStatCacheData()->AddSymlink(std::string(to), strFrom)){
|
||||
S3FS_PRN_ERR("failed to add symbolic link cache for %s", to);
|
||||
}
|
||||
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(to))){
|
||||
S3FS_PRN_ERR("succeed to create symbolic link(%s), but could not update timestamp of its parent directory(result=%d).", to, update_result);
|
||||
}
|
||||
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
return result;
|
||||
@ -1321,6 +1358,7 @@ static int rename_object(const char* from, const char* to, bool update_ctime)
|
||||
if(0 != (result = get_object_attribute(from, &buf, &meta))){
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string strSourcePath = (mount_prefix.empty() && 0 == strcmp("/", from)) ? "//" : from;
|
||||
|
||||
if(update_ctime){
|
||||
@ -1716,6 +1754,17 @@ static int s3fs_rename(const char* _from, const char* _to)
|
||||
result = rename_object_nocopy(from, to, true); // update ctime
|
||||
}
|
||||
}
|
||||
|
||||
// update parent directory timestamp
|
||||
//
|
||||
// [NOTE]
|
||||
// already updated timestamp for original path in above functions.
|
||||
//
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(to))){
|
||||
S3FS_PRN_ERR("succeed to create the file/directory(%s), but could not update timestamp of its parent directory(result=%d).", to, update_result);
|
||||
}
|
||||
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
return result;
|
||||
@ -2151,6 +2200,107 @@ static timespec handle_utimens_special_values(timespec ts, timespec now, timespe
|
||||
}
|
||||
}
|
||||
|
||||
static int update_mctime_parent_directory(const char* _path)
|
||||
{
|
||||
if(!update_parent_dir_stat){
|
||||
// Disable updating parent directory stat.
|
||||
S3FS_PRN_DBG("Updating parent directory stats is disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
WTF8_ENCODE(path)
|
||||
int result;
|
||||
std::string parentpath; // parent directory path
|
||||
std::string nowpath; // now directory object path("dir" or "dir/" or "xxx_$folder$", etc)
|
||||
std::string newpath; // directory path for the current version("dir/")
|
||||
std::string nowcache;
|
||||
headers_t meta;
|
||||
struct stat stbuf;
|
||||
struct timespec mctime;
|
||||
struct timespec atime;
|
||||
dirtype nDirType = DIRTYPE_UNKNOWN;
|
||||
|
||||
S3FS_PRN_INFO2("[path=%s]", path);
|
||||
|
||||
// get parent directory path
|
||||
parentpath = mydirname(path);
|
||||
|
||||
// check & get directory type
|
||||
if(0 != (result = chk_dir_object_type(parentpath.c_str(), newpath, nowpath, nowcache, &meta, &nDirType))){
|
||||
return result;
|
||||
}
|
||||
|
||||
// get directory stat
|
||||
//
|
||||
// [NOTE]
|
||||
// It is assumed that this function is called after the operation on
|
||||
// the file is completed, so there is no need to check the permissions
|
||||
// on the parent directory.
|
||||
//
|
||||
if(0 != (result = get_object_attribute(parentpath.c_str(), &stbuf))){
|
||||
// If there is not the target file(object), result is -ENOENT.
|
||||
return result;
|
||||
}
|
||||
if(!S_ISDIR(stbuf.st_mode)){
|
||||
S3FS_PRN_ERR("path(%s) is not parent directory.", parentpath.c_str());
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
// make atime/mtime/ctime for updating
|
||||
s3fs_realtime(mctime);
|
||||
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, atime);
|
||||
|
||||
if(0 == atime.tv_sec && 0 == atime.tv_nsec){
|
||||
atime = mctime;
|
||||
}
|
||||
|
||||
if(nocopyapi || IS_REPLACEDIR(nDirType) || IS_CREATE_MP_STAT(parentpath.c_str())){
|
||||
// Should rebuild directory object(except new type)
|
||||
// Need to remove old dir("dir" etc) and make new dir("dir/")
|
||||
std::string xattrvalue;
|
||||
const char* pxattrvalue;
|
||||
if(get_meta_xattr_value(path, xattrvalue)){
|
||||
pxattrvalue = xattrvalue.c_str();
|
||||
}else{
|
||||
pxattrvalue = NULL;
|
||||
}
|
||||
|
||||
// At first, remove directory old object
|
||||
if(!nowpath.empty()){
|
||||
if(0 != (result = remove_old_type_dir(nowpath, nDirType))){
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if(!nowcache.empty()){
|
||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||
}
|
||||
|
||||
// Make new directory object("dir/")
|
||||
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, atime, mctime, mctime, stbuf.st_uid, stbuf.st_gid, pxattrvalue))){
|
||||
return result;
|
||||
}
|
||||
}else{
|
||||
std::string strSourcePath = (mount_prefix.empty() && "/" == nowpath) ? "//" : nowpath;
|
||||
headers_t updatemeta;
|
||||
updatemeta["x-amz-meta-mtime"] = str(mctime);
|
||||
updatemeta["x-amz-meta-ctime"] = str(mctime);
|
||||
updatemeta["x-amz-meta-atime"] = str(atime);
|
||||
updatemeta["x-amz-copy-source"] = urlEncode(service_path + S3fsCred::GetBucket() + get_realpath(strSourcePath.c_str()));
|
||||
updatemeta["x-amz-metadata-directive"] = "REPLACE";
|
||||
|
||||
merge_headers(meta, updatemeta, true);
|
||||
|
||||
// upload meta for parent directory.
|
||||
if(0 != (result = put_headers(nowpath.c_str(), meta, true))){
|
||||
return result;
|
||||
}
|
||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||
}
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3fs_utimens(const char* _path, const struct timespec ts[2])
|
||||
{
|
||||
WTF8_ENCODE(path)
|
||||
@ -2681,10 +2831,20 @@ static int s3fs_flush(const char* _path, struct fuse_file_info* fi)
|
||||
AutoFdEntity autoent;
|
||||
FdEntity* ent;
|
||||
if(NULL != (ent = autoent.GetExistFdEntity(path, static_cast<int>(fi->fh)))){
|
||||
bool is_new_file = ent->IsDirtyNewFile();
|
||||
|
||||
ent->UpdateMtime(true); // clear the flag not to update mtime.
|
||||
ent->UpdateCtime();
|
||||
result = ent->Flush(static_cast<int>(fi->fh), AutoLock::NONE, false);
|
||||
StatCache::getStatCacheData()->DelStat(path);
|
||||
|
||||
if(is_new_file){
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(path))){
|
||||
S3FS_PRN_ERR("succeed to create the file(%s), but could not update timestamp of its parent directory(result=%d).", path, update_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
@ -2704,11 +2864,21 @@ static int s3fs_fsync(const char* _path, int datasync, struct fuse_file_info* fi
|
||||
AutoFdEntity autoent;
|
||||
FdEntity* ent;
|
||||
if(NULL != (ent = autoent.GetExistFdEntity(path, static_cast<int>(fi->fh)))){
|
||||
bool is_new_file = ent->IsDirtyNewFile();
|
||||
|
||||
if(0 == datasync){
|
||||
ent->UpdateMtime();
|
||||
ent->UpdateCtime();
|
||||
}
|
||||
result = ent->Flush(static_cast<int>(fi->fh), AutoLock::NONE, false);
|
||||
|
||||
if(is_new_file){
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(path))){
|
||||
S3FS_PRN_ERR("succeed to create the file(%s), but could not update timestamp of its parent directory(result=%d).", path, update_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
S3FS_MALLOCTRIM(0);
|
||||
|
||||
@ -2751,12 +2921,22 @@ static int s3fs_release(const char* _path, struct fuse_file_info* fi)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
bool is_new_file = ent->IsDirtyNewFile();
|
||||
|
||||
// TODO: correct locks held?
|
||||
int result = ent->UploadPending(static_cast<int>(fi->fh), AutoLock::NONE);
|
||||
if(0 != result){
|
||||
S3FS_PRN_ERR("could not upload pending data(meta, etc) for pseudo_fd(%llu) / path(%s)", (unsigned long long)(fi->fh), path);
|
||||
return result;
|
||||
}
|
||||
|
||||
if(is_new_file){
|
||||
// update parent directory timestamp
|
||||
int update_result;
|
||||
if(0 != (update_result = update_mctime_parent_directory(path))){
|
||||
S3FS_PRN_ERR("succeed to create the file(%s), but could not update timestamp of its parent directory(result=%d).", path, update_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check - for debug
|
||||
@ -4214,23 +4394,21 @@ static bool set_mountpoint_attribute(struct stat& mpst)
|
||||
//
|
||||
static int set_bucket(const char* arg)
|
||||
{
|
||||
char* bucket_name = strdup(arg);
|
||||
// TODO: Mutates input. Consider some other tokenization.
|
||||
char *bucket_name = const_cast<char*>(arg);
|
||||
if(strstr(arg, ":")){
|
||||
if(strstr(arg, "://")){
|
||||
S3FS_PRN_EXIT("bucket name and path(\"%s\") is wrong, it must be \"bucket[:/path]\".", arg);
|
||||
free(bucket_name);
|
||||
return -1;
|
||||
}
|
||||
if(!S3fsCred::SetBucket(strtok(bucket_name, ":"))){
|
||||
S3FS_PRN_EXIT("bucket name and path(\"%s\") is wrong, it must be \"bucket[:/path]\".", arg);
|
||||
free(bucket_name);
|
||||
return -1;
|
||||
}
|
||||
char* pmount_prefix = strtok(NULL, "");
|
||||
if(pmount_prefix){
|
||||
if(0 == strlen(pmount_prefix) || '/' != pmount_prefix[0]){
|
||||
S3FS_PRN_EXIT("path(%s) must be prefix \"/\".", pmount_prefix);
|
||||
free(bucket_name);
|
||||
return -1;
|
||||
}
|
||||
mount_prefix = pmount_prefix;
|
||||
@ -4240,11 +4418,9 @@ static int set_bucket(const char* arg)
|
||||
}else{
|
||||
if(!S3fsCred::SetBucket(arg)){
|
||||
S3FS_PRN_EXIT("bucket name and path(\"%s\") is wrong, it must be \"bucket[:/path]\".", arg);
|
||||
free(bucket_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(bucket_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4763,6 +4939,10 @@ static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_ar
|
||||
S3fsCurl::SetUnsignedPayload(true);
|
||||
return 0;
|
||||
}
|
||||
if(0 == strcmp(arg, "update_parent_dir_stat")){
|
||||
update_parent_dir_stat = true;
|
||||
return 0;
|
||||
}
|
||||
if(is_prefix(arg, "host=")){
|
||||
s3host = strchr(arg, '=') + sizeof(char);
|
||||
return 0;
|
||||
|
@ -542,6 +542,12 @@ static const char help_string[] =
|
||||
" check result to that file. The file path parameter can be omitted.\n"
|
||||
" If omitted, the result will be output to stdout or syslog.\n"
|
||||
"\n"
|
||||
" update_parent_dir_stat (default is disable)\n"
|
||||
" The parent directory's mtime and ctime are updated when a file or\n"
|
||||
" directory is created or deleted (when the parent directory's inode is\n"
|
||||
" updated).\n"
|
||||
" By default, parent directory statistics are not updated.\n"
|
||||
"\n"
|
||||
"FUSE/mount Options:\n"
|
||||
"\n"
|
||||
" Most of the generic mount options described in 'man mount' are\n"
|
||||
|
@ -733,7 +733,7 @@ function test_special_characters {
|
||||
# shellcheck disable=SC2010
|
||||
ls 'special~' 2>&1 | grep -q 'No such file or directory'
|
||||
# shellcheck disable=SC2010
|
||||
ls 'specialµ' 2>&1 | grep -q 'No such file or directory'
|
||||
ls 'specialμ' 2>&1 | grep -q 'No such file or directory'
|
||||
)
|
||||
|
||||
mkdir "TOYOTA TRUCK 8.2.2"
|
||||
@ -1292,6 +1292,272 @@ function test_update_chmod_opened_file() {
|
||||
rm_test_file "${ALT_TEST_TEXT_FILE}"
|
||||
}
|
||||
|
||||
function test_update_parent_directory_time_sub() {
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Internal error: parameter is wrong."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# [NOTE]
|
||||
# Skip test for mknod/mkfifo command.
|
||||
# If run them, ctime/mtime of the parent directory will be updated.
|
||||
#
|
||||
local TEST_PARENTDIR_PARENT="${1}"
|
||||
local TEST_PARENTDIR_FILE="${TEST_PARENTDIR_PARENT}/testfile"
|
||||
local TEST_PARENTDIR_SYMFILE_BASE="testfile2"
|
||||
local TEST_PARENTDIR_FILE_MV="${TEST_PARENTDIR_PARENT}/${TEST_PARENTDIR_SYMFILE_BASE}"
|
||||
local TEST_PARENTDIR_SYMFILE="${TEST_PARENTDIR_PARENT}/symfile"
|
||||
local TEST_PARENTDIR_SYMFILE_MV="${TEST_PARENTDIR_PARENT}/symfile2"
|
||||
local TEST_PARENTDIR_DIR="${TEST_PARENTDIR_PARENT}/testdir"
|
||||
local TEST_PARENTDIR_DIR_MV="${TEST_PARENTDIR_PARENT}/testdir2"
|
||||
|
||||
#
|
||||
# Create file -> Update parent directory's mtime/ctime
|
||||
#
|
||||
local base_atime; base_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local base_ctime; base_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local base_mtime; base_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
touch "${TEST_PARENTDIR_FILE}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "creating file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Update file -> Not update parent directory's atime/mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
touch "${TEST_PARENTDIR_FILE}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" != "${after_ctime}" ] || [ "${base_mtime}" != "${after_mtime}" ]; then
|
||||
echo "updating file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} == ${after_ctime} ), mtime( ${base_mtime} == ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Rename file -> Update parent directory's mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
mv "${TEST_PARENTDIR_FILE}" "${TEST_PARENTDIR_FILE_MV}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "renaming file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Create symbolic link -> Update parent directory's mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
ln -s "${TEST_PARENTDIR_SYMFILE_BASE}" "${TEST_PARENTDIR_SYMFILE}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "creating symbolic file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Update symbolic file -> Not update parent directory's atime/mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
touch "${TEST_PARENTDIR_SYMFILE}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" != "${after_ctime}" ] || [ "${base_mtime}" != "${after_mtime}" ]; then
|
||||
echo "updating symbolic file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} == ${after_ctime} ), mtime( ${base_mtime} == ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Rename symbolic link -> Update parent directory's mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
mv "${TEST_PARENTDIR_SYMFILE}" "${TEST_PARENTDIR_SYMFILE_MV}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "renaming symbolic file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Delete symbolic link -> Update parent directory's mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
rm "${TEST_PARENTDIR_SYMFILE_MV}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "deleting symbolic file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Delete file -> Update parent directory's mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
rm "${TEST_PARENTDIR_FILE_MV}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "deleting file expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Create directory -> Update parent directory's mtime/ctime
|
||||
#
|
||||
local base_atime; base_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local base_ctime; base_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local base_mtime; base_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
mkdir "${TEST_PARENTDIR_DIR}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "creating directory expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Update directory -> Not update parent directory's atime/mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
touch "${TEST_PARENTDIR_DIR}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" != "${after_ctime}" ] || [ "${base_mtime}" != "${after_mtime}" ]; then
|
||||
echo "updating directory expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} == ${after_ctime} ), mtime( ${base_mtime} == ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Rename directory -> Update parent directory's mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
mv "${TEST_PARENTDIR_DIR}" "${TEST_PARENTDIR_DIR_MV}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "renaming directory expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Delete directory -> Update parent directory's mtime/ctime
|
||||
#
|
||||
base_atime="${after_atime}"
|
||||
base_ctime="${after_ctime}"
|
||||
base_mtime="${after_mtime}"
|
||||
|
||||
rm -r "${TEST_PARENTDIR_DIR_MV}"
|
||||
|
||||
local after_atime; after_atime=$(get_atime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_ctime; after_ctime=$(get_ctime "${TEST_PARENTDIR_PARENT}")
|
||||
local after_mtime; after_mtime=$(get_mtime "${TEST_PARENTDIR_PARENT}")
|
||||
|
||||
if [ "${base_atime}" != "${after_atime}" ] || [ "${base_ctime}" = "${after_ctime}" ] || [ "${base_mtime}" = "${after_mtime}" ]; then
|
||||
echo "deleting directory expected updating ctime/mtime: atime( ${base_atime} == ${after_atime} ), ctime( ${base_ctime} != ${after_ctime} ), mtime( ${base_mtime} != ${after_mtime} )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function test_update_parent_directory_time() {
|
||||
describe "Testing update time of parent directory..."
|
||||
|
||||
#
|
||||
# Test sub directory
|
||||
#
|
||||
mk_test_dir
|
||||
if ! test_update_parent_directory_time_sub "${TEST_DIR}"; then
|
||||
echo "failed test about updating time of parent directory: ${TEST_DIR}"
|
||||
return 1
|
||||
fi
|
||||
rm -rf "${TEST_DIR}"
|
||||
|
||||
#
|
||||
# Test bucket top directory
|
||||
#
|
||||
# [NOTE]
|
||||
# The current directory for test execution is "<mount point>/testrun-xxxx".
|
||||
# This test checks in the directory at the top of the bucket.
|
||||
#
|
||||
if ! test_update_parent_directory_time_sub ".."; then
|
||||
echo "failed test about updating time of parent directory: ${TEST_DIR}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function test_rm_rf_dir {
|
||||
describe "Test that rm -rf will remove directory with contents ..."
|
||||
# Create a dir with some files and directories
|
||||
@ -2389,7 +2655,10 @@ function add_all_tests {
|
||||
fi
|
||||
add_tests test_update_directory_time_subdir
|
||||
add_tests test_update_chmod_opened_file
|
||||
|
||||
# shellcheck disable=SC2009
|
||||
if ps u -p "${S3FS_PID}" | grep -q update_parent_dir_stat; then
|
||||
add_tests test_update_parent_directory_time
|
||||
fi
|
||||
# shellcheck disable=SC2009
|
||||
if ! ps u -p "${S3FS_PID}" | grep -q use_xattr; then
|
||||
add_tests test_posix_acl
|
||||
|
@ -42,7 +42,7 @@ export CACHE_DIR
|
||||
export ENSURE_DISKFREE_SIZE
|
||||
if [ -n "${ALL_TESTS}" ]; then
|
||||
FLAGS=(
|
||||
"use_cache=${CACHE_DIR} -o ensure_diskfree=${ENSURE_DISKFREE_SIZE} -o fake_diskfree=${FAKE_FREE_DISK_SIZE} -o use_xattr"
|
||||
"use_cache=${CACHE_DIR} -o ensure_diskfree=${ENSURE_DISKFREE_SIZE} -o fake_diskfree=${FAKE_FREE_DISK_SIZE} -o use_xattr -o update_parent_dir_stat"
|
||||
enable_content_md5
|
||||
disable_noobj_cache
|
||||
"max_stat_cache_size=100"
|
||||
|
Loading…
Reference in New Issue
Block a user