Set mtime/ctime/atime of all objects as nanosecond

This commit is contained in:
Takeshi Nakatani 2022-07-25 11:10:04 +00:00 committed by Andrew Gaul
parent ccfc119e45
commit 4b2f3fecb5
12 changed files with 404 additions and 172 deletions

View File

@ -796,13 +796,7 @@ bool convert_header_to_stat(const char* path, const headers_t& meta, struct stat
mtime.tv_sec = 0;
mtime.tv_nsec = 0;
}
#if defined(__APPLE__)
pst->st_mtime = mtime.tv_sec;
pst->st_mtimespec.tv_nsec = mtime.tv_nsec;
#else
pst->st_mtim.tv_sec = mtime.tv_sec;
pst->st_mtim.tv_nsec = mtime.tv_nsec;
#endif
set_timespec_to_stat(*pst, ST_TYPE_MTIME, mtime);
}
// ctime
@ -814,13 +808,7 @@ bool convert_header_to_stat(const char* path, const headers_t& meta, struct stat
ctime.tv_sec = 0;
ctime.tv_nsec = 0;
}
#if defined(__APPLE__)
pst->st_ctime = ctime.tv_sec;
pst->st_ctimespec.tv_nsec = ctime.tv_nsec;
#else
pst->st_ctim.tv_sec = ctime.tv_sec;
pst->st_ctim.tv_nsec = ctime.tv_nsec;
#endif
set_timespec_to_stat(*pst, ST_TYPE_CTIME, ctime);
}
// atime
@ -832,13 +820,7 @@ bool convert_header_to_stat(const char* path, const headers_t& meta, struct stat
atime.tv_sec = 0;
atime.tv_nsec = 0;
}
#if defined(__APPLE__)
pst->st_atime = atime.tv_sec;
pst->st_atimespec.tv_nsec = atime.tv_nsec;
#else
pst->st_atim.tv_sec = atime.tv_sec;
pst->st_atim.tv_nsec = atime.tv_nsec;
#endif
set_timespec_to_stat(*pst, ST_TYPE_ATIME, atime);
}
// size

View File

@ -533,9 +533,9 @@ FdEntity* FdManager::GetFdEntity(const char* path, int& existfd, bool newfd, boo
return NULL;
}
FdEntity* FdManager::Open(int& fd, const char* path, headers_t* pmeta, off_t size, time_t time, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type)
FdEntity* FdManager::Open(int& fd, const char* path, headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type)
{
S3FS_PRN_DBG("[path=%s][size=%lld][time=%lld][flags=0x%x][force_tmpfile=%s][create=%s][ignore_modify=%s]", SAFESTRPTR(path), static_cast<long long>(size), static_cast<long long>(time), flags, (force_tmpfile ? "yes" : "no"), (is_create ? "yes" : "no"), (ignore_modify ? "yes" : "no"));
S3FS_PRN_DBG("[path=%s][size=%lld][ts_mctime=%s][flags=0x%x][force_tmpfile=%s][create=%s][ignore_modify=%s]", SAFESTRPTR(path), static_cast<long long>(size), str(ts_mctime).c_str(), flags, (force_tmpfile ? "yes" : "no"), (is_create ? "yes" : "no"), (ignore_modify ? "yes" : "no"));
if(!path || '\0' == path[0]){
return NULL;
@ -578,7 +578,7 @@ FdEntity* FdManager::Open(int& fd, const char* path, headers_t* pmeta, off_t siz
}
// (re)open
if(-1 == (fd = ent->Open(pmeta, size, time, flags, type))){
if(-1 == (fd = ent->Open(pmeta, size, ts_mctime, flags, type))){
S3FS_PRN_ERR("failed to (re)open and create new pseudo fd for path(%s).", path);
return NULL;
}
@ -594,7 +594,7 @@ FdEntity* FdManager::Open(int& fd, const char* path, headers_t* pmeta, off_t siz
ent = new FdEntity(path, cache_path.c_str());
// open
if(-1 == (fd = ent->Open(pmeta, size, time, flags, type))){
if(-1 == (fd = ent->Open(pmeta, size, ts_mctime, flags, type))){
delete ent;
return NULL;
}
@ -646,7 +646,7 @@ FdEntity* FdManager::OpenExistFdEntity(const char* path, int& fd, int flags)
S3FS_PRN_DBG("[path=%s][flags=0x%x]", SAFESTRPTR(path), flags);
// search entity by path, and create pseudo fd
FdEntity* ent = Open(fd, path, NULL, -1, -1, flags, false, false, false, AutoLock::NONE);
FdEntity* ent = Open(fd, path, NULL, -1, S3FS_OMIT_TS, flags, false, false, false, AutoLock::NONE);
if(!ent){
// Not found entity
return NULL;

View File

@ -87,7 +87,7 @@ class FdManager
// Return FdEntity associated with path, returning NULL on error. This operation increments the reference count; callers must decrement via Close after use.
FdEntity* GetFdEntity(const char* path, int& existfd, bool newfd = true, bool lock_already_held = false);
FdEntity* Open(int& fd, const char* path, headers_t* pmeta, off_t size, time_t time, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type);
FdEntity* Open(int& fd, const char* path, headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type);
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
FdEntity* OpenExistFdEntity(const char* path, int& fd, int flags = O_RDONLY);
void Rename(const std::string &from, const std::string &to);

View File

@ -98,11 +98,11 @@ FdEntity* AutoFdEntity::Attach(const char* path, int existfd)
return pFdEntity;
}
FdEntity* AutoFdEntity::Open(const char* path, headers_t* pmeta, off_t size, time_t time, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type)
FdEntity* AutoFdEntity::Open(const char* path, headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type)
{
Close();
if(NULL == (pFdEntity = FdManager::get()->Open(pseudo_fd, path, pmeta, size, time, flags, force_tmpfile, is_create, ignore_modify, type))){
if(NULL == (pFdEntity = FdManager::get()->Open(pseudo_fd, path, pmeta, size, ts_mctime, flags, force_tmpfile, is_create, ignore_modify, type))){
pseudo_fd = -1;
return NULL;
}

View File

@ -51,7 +51,7 @@ class AutoFdEntity
FdEntity* Attach(const char* path, int existfd);
int GetPseudoFd() const { return pseudo_fd; }
FdEntity* Open(const char* path, headers_t* pmeta, off_t size, time_t time, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type);
FdEntity* Open(const char* path, headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, AutoLock::Type type);
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
FdEntity* OpenExistFdEntity(const char* path, int flags = O_RDONLY);
};

View File

@ -412,11 +412,17 @@ bool FdEntity::IsUploading(bool lock_already_held)
// If the open is successful, returns pseudo fd.
// If it fails, it returns an error code with a negative value.
//
int FdEntity::Open(const headers_t* pmeta, off_t size, time_t time, int flags, AutoLock::Type type)
// ts_mctime argument is a variable for mtime/ctime.
// If you want to disable this variable, specify UTIME_OMIT for
// tv_nsec in timespec member(in this case tv_sec member is ignored).
// This is similar to utimens operation.
// You can use "S3FS_OMIT_TS" global variable for UTIME_OMIT.
//
int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, AutoLock::Type type)
{
AutoLock auto_lock(&fdent_lock, type);
S3FS_PRN_DBG("[path=%s][physical_fd=%d][size=%lld][time=%lld][flags=0x%x]", path.c_str(), physical_fd, static_cast<long long>(size), static_cast<long long>(time), flags);
S3FS_PRN_DBG("[path=%s][physical_fd=%d][size=%lld][ts_mctime=%s][flags=0x%x]", path.c_str(), physical_fd, static_cast<long long>(size), str(ts_mctime).c_str(), flags);
if (!auto_lock.isLockAcquired()) {
// had to wait for fd lock, return
@ -480,7 +486,7 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, time_t time, int flags, A
// using cache
struct stat st;
if(stat(cachepath.c_str(), &st) == 0){
if(st.st_mtime < time){
if(0 > compare_timespec(st, ST_TYPE_MTIME, ts_mctime)){
S3FS_PRN_DBG("cache file stale, removing: %s", cachepath.c_str());
if(unlink(cachepath.c_str()) != 0){
return (0 == errno ? -EIO : -errno);
@ -547,13 +553,13 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, time_t time, int flags, A
}else{
// [NOTE]
// The modify flag must not be set when opening a file,
// if the time parameter(mtime) is specified(not -1) and
// the cache file does not exist.
// if the ts_mctime parameter(mtime) is specified(tv_nsec != UTIME_OMIT)
// and the cache file does not exist.
// If mtime is specified for the file and the cache file
// mtime is older than it, the cache file is removed and
// the processing comes here.
//
pagelist.Resize(size, false, (0 <= time ? false : true));
pagelist.Resize(size, false, (UTIME_OMIT == ts_mctime.tv_nsec ? true : false));
is_truncate = true;
}
@ -597,13 +603,14 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, time_t time, int flags, A
}else{
// [NOTE]
// The modify flag must not be set when opening a file,
// if the time parameter(mtime) is specified(not -1) and
// the cache file does not exist.
// if the ts_mctime parameter(mtime) is specified(tv_nsec != UTIME_OMIT)
// and the cache file does not exist.
// If mtime is specified for the file and the cache file
// mtime is older than it, the cache file is removed and
// the processing comes here.
//
pagelist.Resize(size, false, (0 <= time ? false : true));
pagelist.Resize(size, false, (UTIME_OMIT == ts_mctime.tv_nsec ? true : false));
is_truncate = true;
}
}
@ -644,10 +651,9 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, time_t time, int flags, A
}
// set mtime and ctime(set "x-amz-meta-mtime" and "x-amz-meta-ctime" in orgmeta)
if(-1 != time){
struct timespec ts = {time, 0};
if(0 != SetMCtime(ts, ts, /*lock_already_held=*/ true)){
S3FS_PRN_ERR("failed to set mtime. errno(%d)", errno);
if(UTIME_OMIT != ts_mctime.tv_nsec){
if(0 != SetMCtime(ts_mctime, ts_mctime, /*lock_already_held=*/ true)){
S3FS_PRN_ERR("failed to set mtime/ctime. errno(%d)", errno);
fclose(pfile);
pfile = NULL;
physical_fd = -1;
@ -787,7 +793,7 @@ int FdEntity::SetCtime(struct timespec time, bool lock_already_held)
{
AutoLock auto_lock(&fdent_lock, lock_already_held ? AutoLock::ALREADY_LOCKED : AutoLock::NONE);
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%lld]", path.c_str(), physical_fd, static_cast<long long>(time.tv_sec));
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%s]", path.c_str(), physical_fd, str(time).c_str());
if(-1 == time.tv_sec){
return 0;
@ -800,7 +806,7 @@ int FdEntity::SetAtime(struct timespec time, bool lock_already_held)
{
AutoLock auto_lock(&fdent_lock, lock_already_held ? AutoLock::ALREADY_LOCKED : AutoLock::NONE);
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%lld]", path.c_str(), physical_fd, static_cast<long long>(time.tv_sec));
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%s]", path.c_str(), physical_fd, str(time).c_str());
if(-1 == time.tv_sec){
return 0;
@ -816,34 +822,35 @@ int FdEntity::SetMCtime(struct timespec mtime, struct timespec ctime, bool lock_
{
AutoLock auto_lock(&fdent_lock, lock_already_held ? AutoLock::ALREADY_LOCKED : AutoLock::NONE);
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][mtime=%lld][ctime=%lld]", path.c_str(), physical_fd, static_cast<long long>(mtime.tv_sec), static_cast<long long>(ctime.tv_sec));
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][mtime=%s][ctime=%s]", path.c_str(), physical_fd, str(mtime).c_str(), str(ctime).c_str());
if(mtime.tv_sec < 0 || ctime.tv_sec < 0){
return 0;
}
if(-1 != physical_fd){
struct timeval tv[2];
tv[0].tv_sec = mtime.tv_sec;
tv[0].tv_usec = mtime.tv_nsec / 1000;
tv[1].tv_sec = ctime.tv_sec;
tv[1].tv_usec = ctime.tv_nsec / 1000;
if(-1 == futimes(physical_fd, tv)){
S3FS_PRN_ERR("futimes failed. errno(%d)", errno);
struct timespec ts[2];
ts[0].tv_sec = mtime.tv_sec;
ts[0].tv_nsec = mtime.tv_nsec;
ts[1].tv_sec = ctime.tv_sec;
ts[1].tv_nsec = ctime.tv_nsec;
if(-1 == futimens(physical_fd, ts)){
S3FS_PRN_ERR("futimens failed. errno(%d)", errno);
return -errno;
}
}else if(!cachepath.empty()){
// not opened file yet.
struct timeval n_time[2];
n_time[0].tv_sec = ctime.tv_sec;
n_time[0].tv_usec = ctime.tv_nsec / 1000;
n_time[1].tv_sec = mtime.tv_sec;
n_time[1].tv_usec = mtime.tv_nsec / 1000;
if(-1 == utimes(cachepath.c_str(), n_time)){
S3FS_PRN_ERR("utime failed. errno(%d)", errno);
struct timespec ts[2];
ts[0].tv_sec = ctime.tv_sec;
ts[0].tv_nsec = ctime.tv_nsec;
ts[1].tv_sec = mtime.tv_sec;
ts[1].tv_nsec = mtime.tv_nsec;
if(-1 == utimensat(AT_FDCWD, cachepath.c_str(), ts, 0)){
S3FS_PRN_ERR("utimensat failed. errno(%d)", errno);
return -errno;
}
}
orgmeta["x-amz-meta-mtime"] = str(mtime);
orgmeta["x-amz-meta-ctime"] = str(ctime);
@ -857,7 +864,9 @@ bool FdEntity::UpdateCtime()
if(!GetStats(st, /*lock_already_held=*/ true)){
return false;
}
orgmeta["x-amz-meta-ctime"] = str(st.st_ctime);
orgmeta["x-amz-meta-ctime"] = str_stat_time(st, ST_TYPE_CTIME);
return true;
}
@ -868,7 +877,9 @@ bool FdEntity::UpdateAtime()
if(!GetStats(st, /*lock_already_held=*/ true)){
return false;
}
orgmeta["x-amz-meta-atime"] = str(st.st_atime);
orgmeta["x-amz-meta-atime"] = str_stat_time(st, ST_TYPE_ATIME);
return true;
}
@ -896,7 +907,7 @@ bool FdEntity::UpdateMtime(bool clear_holding_mtime)
if(!GetStats(st, /*lock_already_held=*/ true)){
return false;
}
orgmeta["x-amz-meta-mtime"] = str(st.st_mtime);
orgmeta["x-amz-meta-mtime"] = str_stat_time(st, ST_TYPE_MTIME);
}
return true;
}
@ -905,6 +916,8 @@ bool FdEntity::SetHoldingMtime(struct timespec mtime, bool lock_already_held)
{
AutoLock auto_lock(&fdent_lock, lock_already_held ? AutoLock::ALREADY_LOCKED : AutoLock::NONE);
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][mtime=%s]", path.c_str(), physical_fd, str(mtime).c_str());
if(mtime.tv_sec < 0){
return false;
}
@ -924,34 +937,33 @@ bool FdEntity::ClearHoldingMtime(bool lock_already_held)
return false;
}
if(-1 != physical_fd){
struct timeval tv[2];
tv[0].tv_sec = holding_mtime.tv_sec;
tv[0].tv_usec = holding_mtime.tv_nsec / 1000;
#if defined(__APPLE__)
tv[1].tv_sec = st.st_ctime;
tv[1].tv_usec = st.st_ctimespec.tv_nsec / 1000;
#else
tv[1].tv_sec = st.st_ctim.tv_sec;
tv[1].tv_usec = st.st_ctim.tv_nsec / 1000;
#endif
if(-1 == futimes(physical_fd, tv)){
S3FS_PRN_ERR("futimes failed. errno(%d)", errno);
struct timespec ts[2];
struct timespec ts_ctime;
ts[0].tv_sec = holding_mtime.tv_sec;
ts[0].tv_nsec = holding_mtime.tv_nsec;
set_stat_to_timespec(st, ST_TYPE_CTIME, ts_ctime);
ts[1].tv_sec = ts_ctime.tv_sec;
ts[1].tv_nsec = ts_ctime.tv_nsec;
if(-1 == futimens(physical_fd, ts)){
S3FS_PRN_ERR("futimens failed. errno(%d)", errno);
return false;
}
}else if(!cachepath.empty()){
// not opened file yet.
struct timeval n_time[2];
#if defined(__APPLE__)
n_time[0].tv_sec = st.st_ctime;
n_time[0].tv_usec = st.st_ctimespec.tv_nsec / 1000;
#else
n_time[0].tv_sec = st.st_ctime;
n_time[0].tv_usec = st.st_ctim.tv_nsec / 1000;
#endif
n_time[1].tv_sec = holding_mtime.tv_sec;
n_time[1].tv_usec = holding_mtime.tv_nsec / 1000;
if(-1 == utimes(cachepath.c_str(), n_time)){
S3FS_PRN_ERR("utime failed. errno(%d)", errno);
struct timespec ts[2];
struct timespec ts_ctime;
set_stat_to_timespec(st, ST_TYPE_CTIME, ts_ctime);
ts[0].tv_sec = ts_ctime.tv_sec;
ts[0].tv_nsec = ts_ctime.tv_nsec;
ts[1].tv_sec = holding_mtime.tv_sec;
ts[1].tv_nsec = holding_mtime.tv_nsec;
if(-1 == utimensat(AT_FDCWD, cachepath.c_str(), ts, 0)){
S3FS_PRN_ERR("utimensat failed. errno(%d)", errno);
return false;
}
}

View File

@ -104,7 +104,7 @@ class FdEntity
void Close(int fd);
bool IsOpen() const { return (-1 != physical_fd); }
bool FindPseudoFd(int fd, bool lock_already_held = false);
int Open(const headers_t* pmeta, off_t size, time_t time, int flags, AutoLock::Type type);
int Open(const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, AutoLock::Type type);
bool LoadAll(int fd, headers_t* pmeta = NULL, off_t* size = NULL, bool force_load = false);
int Dup(int fd, bool lock_already_held = false);
int OpenPseudoFd(int flags = O_RDONLY, bool lock_already_held = false);

View File

@ -121,7 +121,7 @@ static int list_bucket(const char* path, S3ObjList& head, const char* delimiter,
static int directory_empty(const char* path);
static int rename_large_object(const char* from, const char* to);
static int create_file_object(const char* path, mode_t mode, uid_t uid, gid_t gid);
static int create_directory_object(const char* path, mode_t mode, time_t atime, time_t mtime, time_t ctime, uid_t uid, gid_t gid);
static int create_directory_object(const char* path, mode_t mode, const struct timespec& ts_atime, const struct timespec& ts_mtime, const struct timespec& ts_ctime, uid_t uid, gid_t gid);
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);
@ -704,10 +704,15 @@ static int get_local_fent(AutoFdEntity& autoent, FdEntity **entity, const char*
}
// open
time_t mtime = (!S_ISREG(stobj.st_mode) && !S_ISLNK(stobj.st_mode)) ? -1 : stobj.st_mtime;
struct timespec st_mctime;
if(!S_ISREG(stobj.st_mode) && !S_ISLNK(stobj.st_mode)){
st_mctime = S3FS_OMIT_TS;
}else{
set_stat_to_timespec(stobj, ST_TYPE_MTIME, st_mctime);
}
bool force_tmpfile = S_ISREG(stobj.st_mode) ? false : true;
if(NULL == (ent = autoent.Open(path, &meta, stobj.st_size, mtime, flags, force_tmpfile, true, false, AutoLock::NONE))){
if(NULL == (ent = autoent.Open(path, &meta, stobj.st_size, st_mctime, flags, force_tmpfile, true, false, AutoLock::NONE))){
S3FS_PRN_ERR("Could not open file. errno(%d)", errno);
return -EIO;
}
@ -856,15 +861,15 @@ 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);
time_t now = time(NULL);
headers_t meta;
std::string strnow = s3fs_str_realtime();
headers_t meta;
meta["Content-Type"] = S3fsCurl::LookupMimeType(std::string(path));
meta["x-amz-meta-uid"] = str(uid);
meta["x-amz-meta-gid"] = str(gid);
meta["x-amz-meta-mode"] = str(mode);
meta["x-amz-meta-atime"] = str(now);
meta["x-amz-meta-ctime"] = str(now);
meta["x-amz-meta-mtime"] = str(now);
meta["x-amz-meta-atime"] = strnow;
meta["x-amz-meta-ctime"] = strnow;
meta["x-amz-meta-mtime"] = strnow;
S3fsCurl s3fscurl(true);
return s3fscurl.PutRequest(path, meta, -1); // fd=-1 means for creating zero byte object.
@ -917,15 +922,15 @@ static int s3fs_create(const char* _path, mode_t mode, struct fuse_file_info* fi
return result;
}
time_t now = time(NULL);
headers_t meta;
std::string strnow = s3fs_str_realtime();
headers_t meta;
meta["Content-Length"] = "0";
meta["x-amz-meta-uid"] = str(pcxt->uid);
meta["x-amz-meta-gid"] = str(pcxt->gid);
meta["x-amz-meta-mode"] = str(mode);
meta["x-amz-meta-atime"] = str(now);
meta["x-amz-meta-mtime"] = str(now);
meta["x-amz-meta-ctime"] = str(now);
meta["x-amz-meta-atime"] = strnow;
meta["x-amz-meta-mtime"] = strnow;
meta["x-amz-meta-ctime"] = strnow;
// [NOTE] set no_truncate flag
// At this point, the file has not been created(uploaded) and
@ -941,7 +946,7 @@ static int s3fs_create(const char* _path, mode_t mode, struct fuse_file_info* fi
AutoFdEntity autoent;
FdEntity* ent;
if(NULL == (ent = autoent.Open(path, &meta, 0, -1, fi->flags, false, true, false, AutoLock::NONE))){
if(NULL == (ent = autoent.Open(path, &meta, 0, S3FS_OMIT_TS, fi->flags, false, true, false, AutoLock::NONE))){
StatCache::getStatCacheData()->DelStat(path);
return -EIO;
}
@ -953,9 +958,9 @@ static int s3fs_create(const char* _path, mode_t mode, struct fuse_file_info* fi
return 0;
}
static int create_directory_object(const char* path, mode_t mode, time_t atime, time_t mtime, time_t ctime, uid_t uid, gid_t gid)
static int create_directory_object(const char* path, mode_t mode, const struct timespec& ts_atime, const struct timespec& ts_mtime, const struct timespec& ts_ctime, uid_t uid, gid_t gid)
{
S3FS_PRN_INFO1("[path=%s][mode=%04o][atime=%lld][mtime=%lld][ctime=%lld][uid=%u][gid=%u]", path, mode, static_cast<long long>(atime), static_cast<long long>(ctime), static_cast<long long>(mtime), (unsigned int)uid, (unsigned int)gid);
S3FS_PRN_INFO1("[path=%s][mode=%04o][atime=%s][mtime=%s][ctime=%s][uid=%u][gid=%u]", path, mode, str(ts_atime).c_str(), str(ts_mtime).c_str(), str(ts_ctime).c_str(), (unsigned int)uid, (unsigned int)gid);
if(!path || '\0' == path[0]){
return -EINVAL;
@ -969,9 +974,9 @@ static int create_directory_object(const char* path, mode_t mode, time_t atime,
meta["x-amz-meta-uid"] = str(uid);
meta["x-amz-meta-gid"] = str(gid);
meta["x-amz-meta-mode"] = str(mode);
meta["x-amz-meta-atime"] = str(atime);
meta["x-amz-meta-mtime"] = str(mtime);
meta["x-amz-meta-ctime"] = str(ctime);
meta["x-amz-meta-atime"] = str(ts_atime);
meta["x-amz-meta-mtime"] = str(ts_mtime);
meta["x-amz-meta-ctime"] = str(ts_ctime);
S3fsCurl s3fscurl;
return s3fscurl.PutRequest(tpath.c_str(), meta, -1); // fd=-1 means for creating zero byte object.
@ -999,7 +1004,9 @@ static int s3fs_mkdir(const char* _path, mode_t mode)
}
return result;
}
time_t now = time(NULL);
struct timespec now;
s3fs_realtime(now);
result = create_directory_object(path, mode, now, now, now, pcxt->uid, pcxt->gid);
StatCache::getStatCacheData()->DelStat(path);
@ -1122,13 +1129,13 @@ static int s3fs_symlink(const char* _from, const char* _to)
return result;
}
time_t now = time(NULL);
headers_t headers;
std::string strnow = s3fs_str_realtime();
headers_t headers;
headers["Content-Type"] = std::string("application/octet-stream"); // Static
headers["x-amz-meta-mode"] = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
headers["x-amz-meta-atime"] = str(now);
headers["x-amz-meta-ctime"] = str(now);
headers["x-amz-meta-mtime"] = str(now);
headers["x-amz-meta-atime"] = strnow;
headers["x-amz-meta-ctime"] = strnow;
headers["x-amz-meta-mtime"] = strnow;
headers["x-amz-meta-uid"] = str(pcxt->uid);
headers["x-amz-meta-gid"] = str(pcxt->gid);
@ -1137,7 +1144,7 @@ static int s3fs_symlink(const char* _from, const char* _to)
{ // scope for AutoFdEntity
AutoFdEntity autoent;
FdEntity* ent;
if(NULL == (ent = autoent.Open(to, &headers, 0, -1, O_RDWR, true, true, false, AutoLock::NONE))){
if(NULL == (ent = autoent.Open(to, &headers, 0, S3FS_OMIT_TS, O_RDWR, true, true, false, AutoLock::NONE))){
S3FS_PRN_ERR("could not open tmpfile(errno=%d)", errno);
return -errno;
}
@ -1192,7 +1199,7 @@ static int rename_object(const char* from, const char* to, bool update_ctime)
s3_realpath = get_realpath(from);
if(update_ctime){
meta["x-amz-meta-ctime"] = str(time(NULL));
meta["x-amz-meta-ctime"] = s3fs_str_realtime();
}
meta["x-amz-copy-source"] = urlEncode(service_path + S3fsCred::GetBucket() + s3_realpath);
meta["Content-Type"] = S3fsCurl::LookupMimeType(std::string(to));
@ -1210,7 +1217,7 @@ static int rename_object(const char* from, const char* to, bool update_ctime)
// no opened fd
if(FdManager::IsCacheDir()){
// create cache file if be needed
ent = autoent.Open(from, &meta, buf.st_size, -1, O_RDONLY, false, true, false, AutoLock::NONE);
ent = autoent.Open(from, &meta, buf.st_size, S3FS_OMIT_TS, O_RDONLY, false, true, false, AutoLock::NONE);
}
if(ent){
struct timespec mtime = get_mtime(meta);
@ -1282,7 +1289,8 @@ static int rename_object_nocopy(const char* from, const char* to, bool update_ct
// update ctime
if(update_ctime){
struct timespec ts = {time(NULL), 0};
struct timespec ts;
s3fs_realtime(ts);
ent->SetCtime(ts);
}
@ -1349,7 +1357,18 @@ static int clone_directory_object(const char* from, const char* to, bool update_
if(0 != (result = get_object_attribute(from, &stbuf))){
return result;
}
result = create_directory_object(to, stbuf.st_mode, stbuf.st_atime, stbuf.st_mtime, (update_ctime ? time(NULL) : stbuf.st_ctime), stbuf.st_uid, stbuf.st_gid);
struct timespec ts_atime;
struct timespec ts_mtime;
struct timespec ts_ctime;
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
if(update_ctime){
s3fs_realtime(ts_ctime);
}else{
set_stat_to_timespec(stbuf, ST_TYPE_CTIME, ts_ctime);
}
result = create_directory_object(to, stbuf.st_mode, ts_atime, ts_mtime, ts_ctime, stbuf.st_uid, stbuf.st_gid);
StatCache::getStatCacheData()->DelStat(to);
@ -1605,13 +1624,20 @@ static int s3fs_chmod(const char* _path, mode_t mode)
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), mode, stbuf.st_atime, stbuf.st_mtime, time(NULL), stbuf.st_uid, stbuf.st_gid))){
struct timespec ts_atime;
struct timespec ts_mtime;
struct timespec ts_ctime;
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
s3fs_realtime(ts_ctime);
if(0 != (result = create_directory_object(newpath.c_str(), mode, ts_atime, ts_mtime, ts_ctime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
// normal object or directory object of newer version
headers_t updatemeta;
updatemeta["x-amz-meta-ctime"] = str(time(NULL));
updatemeta["x-amz-meta-ctime"] = s3fs_str_realtime();
updatemeta["x-amz-meta-mode"] = str(mode);
updatemeta["x-amz-copy-source"] = urlEncode(service_path + S3fsCred::GetBucket() + get_realpath(strpath.c_str()));
updatemeta["x-amz-metadata-directive"] = "REPLACE";
@ -1698,7 +1724,14 @@ static int s3fs_chmod_nocopy(const char* _path, mode_t mode)
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), mode, stbuf.st_atime, stbuf.st_mtime, time(NULL), stbuf.st_uid, stbuf.st_gid))){
struct timespec ts_atime;
struct timespec ts_mtime;
struct timespec ts_ctime;
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
s3fs_realtime(ts_ctime);
if(0 != (result = create_directory_object(newpath.c_str(), mode, ts_atime, ts_mtime, ts_ctime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
@ -1712,7 +1745,8 @@ static int s3fs_chmod_nocopy(const char* _path, mode_t mode)
return result;
}
struct timespec ts = {time(NULL), 0};
struct timespec ts;
s3fs_realtime(ts);
ent->SetCtime(ts);
// Change file mode
@ -1782,12 +1816,19 @@ static int s3fs_chown(const char* _path, uid_t uid, gid_t gid)
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, stbuf.st_atime, stbuf.st_mtime, time(NULL), uid, gid))){
struct timespec ts_atime;
struct timespec ts_mtime;
struct timespec ts_ctime;
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
s3fs_realtime(ts_ctime);
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, ts_atime, ts_mtime, ts_ctime, uid, gid))){
return result;
}
}else{
headers_t updatemeta;
updatemeta["x-amz-meta-ctime"] = str(time(NULL));
updatemeta["x-amz-meta-ctime"] = s3fs_str_realtime();
updatemeta["x-amz-meta-uid"] = str(uid);
updatemeta["x-amz-meta-gid"] = str(gid);
updatemeta["x-amz-copy-source"] = urlEncode(service_path + S3fsCred::GetBucket() + get_realpath(strpath.c_str()));
@ -1882,7 +1923,14 @@ static int s3fs_chown_nocopy(const char* _path, uid_t uid, gid_t gid)
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, stbuf.st_atime, stbuf.st_mtime, time(NULL), uid, gid))){
struct timespec ts_atime;
struct timespec ts_mtime;
struct timespec ts_ctime;
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
s3fs_realtime(ts_ctime);
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, ts_atime, ts_mtime, ts_ctime, uid, gid))){
return result;
}
}else{
@ -1896,7 +1944,8 @@ static int s3fs_chown_nocopy(const char* _path, uid_t uid, gid_t gid)
return result;
}
struct timespec ts = {time(NULL), 0};
struct timespec ts;
s3fs_realtime(ts);
ent->SetCtime(ts);
// Change owner
@ -1937,7 +1986,7 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2])
struct stat stbuf;
dirtype nDirType = DIRTYPE_UNKNOWN;
S3FS_PRN_INFO("[path=%s][mtime=%lld][ctime/atime=%lld]", path, static_cast<long long>(ts[1].tv_sec), static_cast<long long>(ts[0].tv_sec));
S3FS_PRN_INFO("[path=%s][mtime=%s][ctime/atime=%s]", path, str(ts[1]).c_str(), str(ts[0]).c_str());
if(0 == strcmp(path, "/")){
S3FS_PRN_ERR("Could not change mtime for mount point.");
@ -1953,16 +2002,18 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2])
}
struct timespec now;
if(-1 == clock_gettime(static_cast<clockid_t>(CLOCK_REALTIME), &now)){
abort();
}
#if __APPLE__
struct timespec actime = handle_utimens_special_values(ts[0], now, stbuf.st_ctimespec);
struct timespec mtime = handle_utimens_special_values(ts[1], now, stbuf.st_mtimespec);
#else
struct timespec actime = handle_utimens_special_values(ts[0], now, stbuf.st_ctim);
struct timespec mtime = handle_utimens_special_values(ts[1], now, stbuf.st_mtim);
#endif
struct timespec ts_atime;
struct timespec ts_ctime;
struct timespec ts_mtime;
s3fs_realtime(now);
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_CTIME, ts_ctime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
struct timespec atime = handle_utimens_special_values(ts[0], now, ts_atime);
struct timespec ctime = handle_utimens_special_values(ts[0], now, ts_ctime);
struct timespec mtime = handle_utimens_special_values(ts[1], now, ts_mtime);
if(S_ISDIR(stbuf.st_mode)){
result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
@ -1986,14 +2037,14 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2])
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, actime.tv_sec, mtime.tv_sec, actime.tv_sec, stbuf.st_uid, stbuf.st_gid))){
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, atime, mtime, ctime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
headers_t updatemeta;
updatemeta["x-amz-meta-mtime"] = str(mtime);
updatemeta["x-amz-meta-ctime"] = str(actime);
updatemeta["x-amz-meta-atime"] = str(actime);
updatemeta["x-amz-meta-ctime"] = str(ctime);
updatemeta["x-amz-meta-atime"] = str(atime);
updatemeta["x-amz-copy-source"] = urlEncode(service_path + S3fsCred::GetBucket() + get_realpath(strpath.c_str()));
updatemeta["x-amz-metadata-directive"] = "REPLACE";
@ -2059,7 +2110,7 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2])
struct stat stbuf;
dirtype nDirType = DIRTYPE_UNKNOWN;
S3FS_PRN_INFO1("[path=%s][mtime=%lld][atime/ctime=%lld]", path, static_cast<long long>(ts[1].tv_sec), static_cast<long long>(ts[0].tv_sec));
S3FS_PRN_INFO1("[path=%s][mtime=%s][atime/ctime=%s]", path, str(ts[1]).c_str(), str(ts[0]).c_str());
if(0 == strcmp(path, "/")){
S3FS_PRN_ERR("Could not change mtime for mount point.");
@ -2075,16 +2126,18 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2])
}
struct timespec now;
if(-1 == clock_gettime(static_cast<clockid_t>(CLOCK_REALTIME), &now)){
abort();
}
#if __APPLE__
struct timespec actime = handle_utimens_special_values(ts[0], now, stbuf.st_ctimespec);
struct timespec mtime = handle_utimens_special_values(ts[1], now, stbuf.st_mtimespec);
#else
struct timespec actime = handle_utimens_special_values(ts[0], now, stbuf.st_ctim);
struct timespec mtime = handle_utimens_special_values(ts[1], now, stbuf.st_mtim);
#endif
struct timespec ts_atime;
struct timespec ts_ctime;
struct timespec ts_mtime;
s3fs_realtime(now);
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_CTIME, ts_ctime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
struct timespec atime = handle_utimens_special_values(ts[0], now, ts_atime);
struct timespec ctime = handle_utimens_special_values(ts[0], now, ts_ctime);
struct timespec mtime = handle_utimens_special_values(ts[1], now, ts_mtime);
// Get attributes
if(S_ISDIR(stbuf.st_mode)){
@ -2109,7 +2162,7 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2])
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, actime.tv_sec, mtime.tv_sec, actime.tv_sec, stbuf.st_uid, stbuf.st_gid))){
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, atime, mtime, ctime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
@ -2124,13 +2177,13 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2])
}
// set mtime/ctime
if(0 != (result = ent->SetMCtime(mtime, actime))){
if(0 != (result = ent->SetMCtime(mtime, ctime))){
S3FS_PRN_ERR("could not set mtime and ctime to file(%s): result=%d", strpath.c_str(), result);
return result;
}
// set atime
if(0 != (result = ent->SetAtime(actime))){
if(0 != (result = ent->SetAtime(atime))){
S3FS_PRN_ERR("could not set atime to file(%s): result=%d", strpath.c_str(), result);
return result;
}
@ -2198,7 +2251,7 @@ static int s3fs_truncate(const char* _path, off_t size)
ignore_modify = true;
}
if(NULL == (ent = autoent.Open(path, &meta, size, -1, O_RDWR, false, true, ignore_modify, AutoLock::NONE))){
if(NULL == (ent = autoent.Open(path, &meta, size, S3FS_OMIT_TS, O_RDWR, false, true, ignore_modify, AutoLock::NONE))){
S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno);
return -EIO;
}
@ -2224,15 +2277,16 @@ static int s3fs_truncate(const char* _path, off_t size)
if(NULL == (pcxt = fuse_get_context())){
return -EIO;
}
time_t now = time(NULL);
std::string strnow = s3fs_str_realtime();
meta["Content-Type"] = std::string("application/octet-stream"); // Static
meta["x-amz-meta-mode"] = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
meta["x-amz-meta-ctime"] = str(now);
meta["x-amz-meta-mtime"] = str(now);
meta["x-amz-meta-ctime"] = strnow;
meta["x-amz-meta-mtime"] = strnow;
meta["x-amz-meta-uid"] = str(pcxt->uid);
meta["x-amz-meta-gid"] = str(pcxt->gid);
if(NULL == (ent = autoent.Open(path, &meta, size, -1, O_RDWR, true, true, false, AutoLock::NONE))){
if(NULL == (ent = autoent.Open(path, &meta, size, S3FS_OMIT_TS, O_RDWR, true, true, false, AutoLock::NONE))){
S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno);
return -EIO;
}
@ -2302,15 +2356,20 @@ static int s3fs_open(const char* _path, struct fuse_file_info* fi)
if(0 != (result = get_object_attribute(path, NULL, &meta, true, NULL, true))){ // no truncate cache
return result;
}
if(NULL == (ent = autoent.Open(path, &meta, st.st_size, st.st_mtime, fi->flags, false, true, false, AutoLock::NONE))){
struct timespec st_mctime;
set_stat_to_timespec(st, ST_TYPE_MTIME, st_mctime);
if(NULL == (ent = autoent.Open(path, &meta, st.st_size, st_mctime, fi->flags, false, true, false, AutoLock::NONE))){
StatCache::getStatCacheData()->DelStat(path);
return -EIO;
}
if (needs_flush){
time_t now = time(NULL);
struct timespec ts = {now, 0};
struct timespec ts;
s3fs_realtime(ts);
ent->SetMCtime(ts, ts);
if(0 != (result = ent->RowFlush(autoent.GetPseudoFd(), path, AutoLock::NONE, true))){
S3FS_PRN_ERR("could not upload file(%s): result=%d", path, result);
StatCache::getStatCacheData()->DelStat(path);
@ -3070,8 +3129,15 @@ static int s3fs_setxattr(const char* path, const char* name, const char* value,
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, stbuf.st_atime, stbuf.st_mtime, stbuf.st_ctime, stbuf.st_uid, stbuf.st_gid))){
return result;
struct timespec ts_atime;
struct timespec ts_mtime;
struct timespec ts_ctime;
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
set_stat_to_timespec(stbuf, ST_TYPE_CTIME, ts_ctime);
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, ts_atime, ts_mtime, ts_ctime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
// need to set xattr header for directory.
@ -3081,7 +3147,7 @@ static int s3fs_setxattr(const char* path, const char* name, const char* value,
// set xattr all object
headers_t updatemeta;
updatemeta["x-amz-meta-ctime"] = str(time(NULL));
updatemeta["x-amz-meta-ctime"] = s3fs_str_realtime();
updatemeta["x-amz-copy-source"] = urlEncode(service_path + S3fsCred::GetBucket() + get_realpath(strpath.c_str()));
updatemeta["x-amz-metadata-directive"] = "REPLACE";
@ -3351,7 +3417,14 @@ static int s3fs_removexattr(const char* path, const char* name)
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, stbuf.st_atime, stbuf.st_mtime, stbuf.st_ctime, stbuf.st_uid, stbuf.st_gid))){
struct timespec ts_atime;
struct timespec ts_mtime;
struct timespec ts_ctime;
set_stat_to_timespec(stbuf, ST_TYPE_ATIME, ts_atime);
set_stat_to_timespec(stbuf, ST_TYPE_MTIME, ts_mtime);
set_stat_to_timespec(stbuf, ST_TYPE_CTIME, ts_ctime);
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, ts_atime, ts_mtime, ts_ctime, stbuf.st_uid, stbuf.st_gid))){
free_xattrs(xattrs);
return result;
}

View File

@ -447,6 +447,129 @@ void print_launch_message(int argc, char** argv)
S3FS_PRN_LAUNCH_INFO("%s", message.c_str());
}
//-------------------------------------------------------------------
// Utility for nanosecond time(timespec)
//-------------------------------------------------------------------
const struct timespec S3FS_OMIT_TS = {0, UTIME_OMIT};
//
// result: -1 ts1 < ts2
// 0 ts1 == ts2
// 1 ts1 > ts2
//
int compare_timespec(const struct timespec& ts1, const struct timespec& ts2)
{
if(ts1.tv_sec < ts2.tv_sec){
return -1;
}else if(ts1.tv_sec > ts2.tv_sec){
return 1;
}else{
if(ts1.tv_nsec < ts2.tv_nsec){
return -1;
}else if(ts1.tv_nsec > ts2.tv_nsec){
return 1;
}
}
return 0;
}
//
// result: -1 st < ts
// 0 st == ts
// 1 st > ts
//
int compare_timespec(const struct stat& st, stat_time_type type, const struct timespec& ts)
{
struct timespec st_ts;
set_stat_to_timespec(st, type, st_ts);
return compare_timespec(st_ts, ts);
}
void set_timespec_to_stat(struct stat& st, stat_time_type type, const struct timespec& ts)
{
if(ST_TYPE_ATIME == type){
#if defined(__APPLE__)
st.st_atime = ts.tv_sec;
st.st_atimespec.tv_nsec = ts.tv_nsec;
#else
st.st_atim.tv_sec = ts.tv_sec;
st.st_atim.tv_nsec = ts.tv_nsec;
#endif
}else if(ST_TYPE_MTIME == type){
#if defined(__APPLE__)
st.st_mtime = ts.tv_sec;
st.st_mtimespec.tv_nsec = ts.tv_nsec;
#else
st.st_mtim.tv_sec = ts.tv_sec;
st.st_mtim.tv_nsec = ts.tv_nsec;
#endif
}else if(ST_TYPE_CTIME == type){
#if defined(__APPLE__)
st.st_ctime = ts.tv_sec;
st.st_ctimespec.tv_nsec = ts.tv_nsec;
#else
st.st_ctim.tv_sec = ts.tv_sec;
st.st_ctim.tv_nsec = ts.tv_nsec;
#endif
}else{
S3FS_PRN_ERR("unknown type(%d), so skip to set value.", type);
}
}
struct timespec* set_stat_to_timespec(const struct stat& st, stat_time_type type, struct timespec& ts)
{
if(ST_TYPE_ATIME == type){
#if defined(__APPLE__)
ts.tv_sec = st.st_atime;
ts.tv_nsec = st.st_atimespec.tv_nsec;
#else
ts = st.st_atim;
#endif
}else if(ST_TYPE_MTIME == type){
#if defined(__APPLE__)
ts.tv_sec = st.st_mtime;
ts.tv_nsec = st.st_mtimespec.tv_nsec;
#else
ts = st.st_mtim;
#endif
}else if(ST_TYPE_CTIME == type){
#if defined(__APPLE__)
ts.tv_sec = st.st_ctime;
ts.tv_nsec = st.st_ctimespec.tv_nsec;
#else
ts = st.st_ctim;
#endif
}else{
S3FS_PRN_ERR("unknown type(%d), so use 0 as timespec.", type);
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
return &ts;
}
std::string str_stat_time(const struct stat& st, stat_time_type type)
{
struct timespec ts;
return str(*set_stat_to_timespec(st, type, ts));
}
struct timespec* s3fs_realtime(struct timespec& ts)
{
if(-1 == clock_gettime(static_cast<clockid_t>(CLOCK_REALTIME), &ts)){
S3FS_PRN_WARN("failed to clock_gettime by errno(%d)", errno);
ts.tv_sec = time(NULL);
ts.tv_nsec = 0;
}
return &ts;
}
std::string s3fs_str_realtime()
{
struct timespec ts;
return str(*(s3fs_realtime(ts)));
}
/*
* Local variables:
* tab-width: 4

View File

@ -56,6 +56,24 @@ bool compare_sysname(const char* target);
void print_launch_message(int argc, char** argv);
//
// Utility for nanosecond time(timespec)
//
enum stat_time_type{
ST_TYPE_ATIME,
ST_TYPE_MTIME,
ST_TYPE_CTIME
};
extern const struct timespec S3FS_OMIT_TS;
int compare_timespec(const struct timespec& ts1, const struct timespec& ts2);
int compare_timespec(const struct stat& st, stat_time_type type, const struct timespec& ts);
void set_timespec_to_stat(struct stat& st, stat_time_type type, const struct timespec& ts);
struct timespec* set_stat_to_timespec(const struct stat& st, stat_time_type type, struct timespec& ts);
std::string str_stat_time(const struct stat& st, stat_time_type type);
struct timespec* s3fs_realtime(struct timespec& ts);
std::string s3fs_str_realtime();
#endif // S3FS_S3FS_UTIL_H_
/*

View File

@ -56,7 +56,8 @@ template std::string str(unsigned long value);
template std::string str(long long value);
template std::string str(unsigned long long value);
template<> std::string str(struct timespec value) {
template<> std::string str(const struct timespec value)
{
std::ostringstream s;
s << value.tv_sec;
if(value.tv_nsec != 0){

View File

@ -824,16 +824,39 @@ function test_mtime_file {
# create the test file again
mk_test_file
sleep 1 # allow for some time to pass to compare the timestamps between test & alt
#copy the test file with preserve mode
cp -p "${TEST_TEXT_FILE}" "${ALT_TEST_TEXT_FILE}"
local testmtime; testmtime=$(get_mtime "${TEST_TEXT_FILE}")
local testctime; testctime=$(get_ctime "${TEST_TEXT_FILE}")
local testatime; testatime=$(get_atime "${TEST_TEXT_FILE}")
local altmtime; altmtime=$(get_mtime "${ALT_TEST_TEXT_FILE}")
if [ "${testmtime}" != "${altmtime}" ]
then
echo "File times do not match: $testmtime != $altmtime"
return 1
local altctime; altctime=$(get_ctime "${ALT_TEST_TEXT_FILE}")
local altatime; altatime=$(get_atime "${ALT_TEST_TEXT_FILE}")
if [ "${testmtime}" != "${altmtime}" ] || [ "${testctime}" = "${altctime}" ] || [ "${testatime}" != "${altatime}" ]; then
# [NOTE]{FIXME]
# On macos10, the mtime of the file copied by "cp -p" is
# truncated to usec from nsec, and it cannot be solved.
# This is because the timespec.tv_sec value of the mtime
# of the original file is truncated in usec units at calling
# s3fs_utimens.
# (ex. "1658768609.505917125" vs "1658768609.505917000")
# Now this workaround is not found, so for macos compare
# mtime with only usec.
#
if ! uname | grep -q Darwin; then
echo "cp(-p) expected times: mtime( ${testmtime} == ${altmtime} ), ctime( ${testctime} != ${altctime} ), atime( ${testatime} == ${altatime} )"
return 1
else
testmtime=$(echo "${testmtime}" | cut -c 1-17)
altmtime=$(echo "${altmtime}" | cut -c 1-17)
if [ "${testmtime}" != "${altmtime}" ] || [ "${testctime}" = "${altctime}" ] || [ "${testatime}" != "${altatime}" ]; then
echo "cp(-p) expected times: mtime( ${testmtime} == ${altmtime} ), ctime( ${testctime} != ${altctime} ), atime( ${testatime} == ${altatime} )"
return 1
fi
fi
fi
rm_test_file