diff --git a/src/cache.cpp b/src/cache.cpp index 46f817f..22bcd31 100644 --- a/src/cache.cpp +++ b/src/cache.cpp @@ -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 diff --git a/src/fdcache.cpp b/src/fdcache.cpp index 3e79746..3171140 100644 --- a/src/fdcache.cpp +++ b/src/fdcache.cpp @@ -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(size), static_cast(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(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; diff --git a/src/fdcache.h b/src/fdcache.h index 9227f17..d22600d 100644 --- a/src/fdcache.h +++ b/src/fdcache.h @@ -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); diff --git a/src/fdcache_auto.cpp b/src/fdcache_auto.cpp index 54d8e0a..dad2f85 100644 --- a/src/fdcache_auto.cpp +++ b/src/fdcache_auto.cpp @@ -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; } diff --git a/src/fdcache_auto.h b/src/fdcache_auto.h index 02523be..9b2daca 100644 --- a/src/fdcache_auto.h +++ b/src/fdcache_auto.h @@ -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); }; diff --git a/src/fdcache_entity.cpp b/src/fdcache_entity.cpp index d087d96..d199b40 100644 --- a/src/fdcache_entity.cpp +++ b/src/fdcache_entity.cpp @@ -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(size), static_cast(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(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(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(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(mtime.tv_sec), static_cast(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; } } diff --git a/src/fdcache_entity.h b/src/fdcache_entity.h index fc0201f..705b64b 100644 --- a/src/fdcache_entity.h +++ b/src/fdcache_entity.h @@ -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); diff --git a/src/s3fs.cpp b/src/s3fs.cpp index 2f42e95..6e98837 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -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(atime), static_cast(ctime), static_cast(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(ts[1].tv_sec), static_cast(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(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(ts[1].tv_sec), static_cast(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(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; } diff --git a/src/s3fs_util.cpp b/src/s3fs_util.cpp index 23a2c7f..f1d57a1 100644 --- a/src/s3fs_util.cpp +++ b/src/s3fs_util.cpp @@ -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(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 diff --git a/src/s3fs_util.h b/src/s3fs_util.h index 243548e..4b69b06 100644 --- a/src/s3fs_util.h +++ b/src/s3fs_util.h @@ -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_ /* diff --git a/src/string_util.cpp b/src/string_util.cpp index b0e4d6c..1f9ce7e 100644 --- a/src/string_util.cpp +++ b/src/string_util.cpp @@ -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){ diff --git a/test/integration-test-main.sh b/test/integration-test-main.sh index 440e1ad..57a1072 100755 --- a/test/integration-test-main.sh +++ b/test/integration-test-main.sh @@ -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