Changed file stat times(a/c/mtime) management
This commit is contained in:
committed by
Andrew Gaul
parent
60fb557f14
commit
37e593aeb0
@ -53,6 +53,7 @@ s3fs_SOURCES = \
|
|||||||
fdcache_fdinfo.cpp \
|
fdcache_fdinfo.cpp \
|
||||||
fdcache_pseudofd.cpp \
|
fdcache_pseudofd.cpp \
|
||||||
fdcache_untreated.cpp \
|
fdcache_untreated.cpp \
|
||||||
|
filetimes.cpp \
|
||||||
addhead.cpp \
|
addhead.cpp \
|
||||||
sighandlers.cpp \
|
sighandlers.cpp \
|
||||||
threadpoolman.cpp \
|
threadpoolman.cpp \
|
||||||
|
|||||||
@ -527,9 +527,9 @@ FdEntity* FdManager::GetFdEntityHasLock(const char* path, int& existfd, bool new
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
FdEntity* FdManager::Open(int& fd, const char* path, const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify)
|
FdEntity* FdManager::Open(int& fd, const char* path, const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags, bool force_tmpfile, bool is_create, bool ignore_modify)
|
||||||
{
|
{
|
||||||
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"));
|
S3FS_PRN_DBG("[path=%s][size=%lld][ctime=%s,atime=%s,mtime=%s][flags=0x%x][force_tmpfile=%s][create=%s][ignore_modify=%s]", SAFESTRPTR(path), static_cast<long long>(size), str(ts_times.ctime()).c_str(), str(ts_times.atime()).c_str(), str(ts_times.mtime()).c_str(), flags, (force_tmpfile ? "yes" : "no"), (is_create ? "yes" : "no"), (ignore_modify ? "yes" : "no"));
|
||||||
|
|
||||||
if(!path || '\0' == path[0]){
|
if(!path || '\0' == path[0]){
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -573,7 +573,7 @@ FdEntity* FdManager::Open(int& fd, const char* path, const headers_t* pmeta, off
|
|||||||
}
|
}
|
||||||
|
|
||||||
// (re)open
|
// (re)open
|
||||||
if(0 > (fd = ent->Open(pmeta, size, ts_mctime, flags))){
|
if(0 > (fd = ent->Open(pmeta, size, ts_times, flags))){
|
||||||
S3FS_PRN_ERR("failed to (re)open and create new pseudo fd for path(%s).", path);
|
S3FS_PRN_ERR("failed to (re)open and create new pseudo fd for path(%s).", path);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -590,7 +590,7 @@ FdEntity* FdManager::Open(int& fd, const char* path, const headers_t* pmeta, off
|
|||||||
auto ent = std::make_shared<FdEntity>(path, cache_path.c_str());
|
auto ent = std::make_shared<FdEntity>(path, cache_path.c_str());
|
||||||
|
|
||||||
// open
|
// open
|
||||||
if(0 > (fd = ent->Open(pmeta, size, ts_mctime, flags))){
|
if(0 > (fd = ent->Open(pmeta, size, ts_times, flags))){
|
||||||
S3FS_PRN_ERR("failed to open and create new pseudo fd for path(%s) errno:%d.", path, fd);
|
S3FS_PRN_ERR("failed to open and create new pseudo fd for path(%s) errno:%d.", path, fd);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -656,7 +656,15 @@ FdEntity* FdManager::OpenExistFdEntity(const char* path, int& fd, int flags)
|
|||||||
S3FS_PRN_DBG("[path=%s][flags=0x%x]", SAFESTRPTR(path), flags);
|
S3FS_PRN_DBG("[path=%s][flags=0x%x]", SAFESTRPTR(path), flags);
|
||||||
|
|
||||||
// search entity by path, and create pseudo fd
|
// search entity by path, and create pseudo fd
|
||||||
FdEntity* ent = Open(fd, path, nullptr, -1, S3FS_OMIT_TS, flags, false, false, false);
|
//
|
||||||
|
// [NOTE]
|
||||||
|
// The file timespec is set to UIMTE_OMIT.
|
||||||
|
// This means that if the file is already open(this method is called
|
||||||
|
// when expected to be open), the timespecs will not be updated.
|
||||||
|
// If the file is not open, the current time will be applied.
|
||||||
|
//
|
||||||
|
FdEntity* ent = Open(fd, path, nullptr, -1, FileTimes(), flags, false, false, false);
|
||||||
|
|
||||||
if(!ent){
|
if(!ent){
|
||||||
// Not found entity
|
// Not found entity
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@ -111,7 +111,7 @@ class FdManager
|
|||||||
return GetFdEntityHasLock(path, existfd, newfd);
|
return GetFdEntityHasLock(path, existfd, newfd);
|
||||||
}
|
}
|
||||||
FdEntity* GetFdEntityHasLock(const char* path, int& existfd, bool newfd = true) REQUIRES(FdManager::fd_manager_lock);
|
FdEntity* GetFdEntityHasLock(const char* path, int& existfd, bool newfd = true) REQUIRES(FdManager::fd_manager_lock);
|
||||||
FdEntity* Open(int& fd, const char* path, const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify);
|
FdEntity* Open(int& fd, const char* path, const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags, bool force_tmpfile, bool is_create, bool ignore_modify);
|
||||||
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
|
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
|
||||||
FdEntity* OpenExistFdEntity(const char* path, int& fd, int flags = O_RDONLY);
|
FdEntity* OpenExistFdEntity(const char* path, int& fd, int flags = O_RDONLY);
|
||||||
void Rename(const std::string &from, const std::string &to);
|
void Rename(const std::string &from, const std::string &to);
|
||||||
|
|||||||
@ -78,11 +78,11 @@ FdEntity* AutoFdEntity::Attach(const char* path, int existfd)
|
|||||||
return pFdEntity;
|
return pFdEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
FdEntity* AutoFdEntity::Open(const char* path, const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, int* error)
|
FdEntity* AutoFdEntity::Open(const char* path, const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, int* error)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
if(nullptr == (pFdEntity = FdManager::get()->Open(pseudo_fd, path, pmeta, size, ts_mctime, flags, force_tmpfile, is_create, ignore_modify))){
|
if(nullptr == (pFdEntity = FdManager::get()->Open(pseudo_fd, path, pmeta, size, ts_times, flags, force_tmpfile, is_create, ignore_modify))){
|
||||||
if(error){
|
if(error){
|
||||||
*error = pseudo_fd;
|
*error = pseudo_fd;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "metaheader.h"
|
#include "metaheader.h"
|
||||||
|
#include "filetimes.h"
|
||||||
|
|
||||||
class FdEntity;
|
class FdEntity;
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ class AutoFdEntity
|
|||||||
FdEntity* Attach(const char* path, int existfd);
|
FdEntity* Attach(const char* path, int existfd);
|
||||||
int GetPseudoFd() const { return pseudo_fd; }
|
int GetPseudoFd() const { return pseudo_fd; }
|
||||||
|
|
||||||
FdEntity* Open(const char* path, const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, int* error = nullptr);
|
FdEntity* Open(const char* path, const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, int* error = nullptr);
|
||||||
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
|
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
|
||||||
FdEntity* OpenExistFdEntity(const char* path, int flags = O_RDONLY);
|
FdEntity* OpenExistFdEntity(const char* path, int flags = O_RDONLY);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -119,8 +119,6 @@ FdEntity::FdEntity(const char* tpath, const char* cpath) :
|
|||||||
cachepath(SAFESTRPTR(cpath)), pending_status(pending_status_t::NO_UPDATE_PENDING),
|
cachepath(SAFESTRPTR(cpath)), pending_status(pending_status_t::NO_UPDATE_PENDING),
|
||||||
ro_path(SAFESTRPTR(tpath))
|
ro_path(SAFESTRPTR(tpath))
|
||||||
{
|
{
|
||||||
holding_mtime.tv_sec = -1;
|
|
||||||
holding_mtime.tv_nsec = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FdEntity::~FdEntity()
|
FdEntity::~FdEntity()
|
||||||
@ -168,6 +166,8 @@ void FdEntity::Clear()
|
|||||||
// set backup(read only) variable
|
// set backup(read only) variable
|
||||||
const std::lock_guard<std::mutex> ro_lock(ro_path_lock);
|
const std::lock_guard<std::mutex> ro_lock(ro_path_lock);
|
||||||
ro_path = path;
|
ro_path = path;
|
||||||
|
|
||||||
|
timestamps.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// [NOTE]
|
// [NOTE]
|
||||||
@ -380,18 +380,18 @@ bool FdEntity::IsUploading()
|
|||||||
// If the open is successful, returns pseudo fd.
|
// If the open is successful, returns pseudo fd.
|
||||||
// If it fails, it returns an error code with a negative value.
|
// If it fails, it returns an error code with a negative value.
|
||||||
//
|
//
|
||||||
// ts_mctime argument is a variable for mtime/ctime.
|
// The ts_times argument is a variable for atime/mtime/ctime.
|
||||||
// If you want to disable this variable, specify UTIME_OMIT for
|
// If you want to disable each value, set the tv_nsec of the timespec
|
||||||
// tv_nsec in timespec member(in this case tv_sec member is ignored).
|
// member corresponding to atime/ctime/mtime to UTIME_OMIT. (In this
|
||||||
// This is similar to utimens operation.
|
// case, the tv_sec member will be ignored.)
|
||||||
// You can use "S3FS_OMIT_TS" global variable for UTIME_OMIT.
|
// This is the same as the behavior of utimens.
|
||||||
//
|
//
|
||||||
int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags)
|
int FdEntity::Open(const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags)
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
const std::lock_guard<std::mutex> lock(fdent_lock);
|
||||||
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
||||||
|
|
||||||
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);
|
S3FS_PRN_DBG("[path=%s][physical_fd=%d][size=%lld][ctime=%s,atime=%s,mtime=%s][flags=0x%x]", path.c_str(), physical_fd, static_cast<long long>(size), str(ts_times.ctime()).c_str(), str(ts_times.atime()).c_str(), str(ts_times.mtime()).c_str(), flags);
|
||||||
|
|
||||||
// [NOTE]
|
// [NOTE]
|
||||||
// When the file size is incremental by truncating, it must be keeped
|
// When the file size is incremental by truncating, it must be keeped
|
||||||
@ -440,6 +440,7 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts
|
|||||||
//
|
//
|
||||||
bool need_save_csf = false; // need to save(reset) cache stat file
|
bool need_save_csf = false; // need to save(reset) cache stat file
|
||||||
bool is_truncate = false; // need to truncate
|
bool is_truncate = false; // need to truncate
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
std::unique_ptr<CacheFileStat> pcfstat;
|
std::unique_ptr<CacheFileStat> pcfstat;
|
||||||
|
|
||||||
@ -447,7 +448,8 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts
|
|||||||
// using cache
|
// using cache
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if(stat(cachepath.c_str(), &st) == 0){
|
if(stat(cachepath.c_str(), &st) == 0){
|
||||||
if(0 > compare_timespec(st, stat_time_type::MTIME, ts_mctime)){
|
// check if the cache file stale
|
||||||
|
if(!ts_times.IsOmitMTime() && 0 > compare_timespec(st, stat_time_type::MTIME, ts_times.mtime())){
|
||||||
S3FS_PRN_DBG("cache file stale, removing: %s", cachepath.c_str());
|
S3FS_PRN_DBG("cache file stale, removing: %s", cachepath.c_str());
|
||||||
if(unlink(cachepath.c_str()) != 0){
|
if(unlink(cachepath.c_str()) != 0){
|
||||||
return (0 == errno ? -EIO : -errno);
|
return (0 == errno ? -EIO : -errno);
|
||||||
@ -504,7 +506,6 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts
|
|||||||
S3FS_PRN_ERR("failed to open file(%s). errno(%d)", cachepath.c_str(), errno);
|
S3FS_PRN_ERR("failed to open file(%s). errno(%d)", cachepath.c_str(), errno);
|
||||||
|
|
||||||
// remove cache stat file if it is existed
|
// remove cache stat file if it is existed
|
||||||
int result;
|
|
||||||
if(0 != (result = CacheFileStat::DeleteCacheFileStat(path.c_str()))){
|
if(0 != (result = CacheFileStat::DeleteCacheFileStat(path.c_str()))){
|
||||||
if(-ENOENT != result){
|
if(-ENOENT != result){
|
||||||
S3FS_PRN_WARN("failed to delete current cache stat file(%s) by errno(%d), but continue...", path.c_str(), result);
|
S3FS_PRN_WARN("failed to delete current cache stat file(%s) by errno(%d), but continue...", path.c_str(), result);
|
||||||
@ -520,14 +521,13 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts
|
|||||||
}else{
|
}else{
|
||||||
// [NOTE]
|
// [NOTE]
|
||||||
// The modify flag must not be set when opening a file,
|
// The modify flag must not be set when opening a file,
|
||||||
// if the ts_mctime parameter(mtime) is specified(tv_nsec != UTIME_OMIT)
|
// if the ts_times parameter(mtime) is specified(tv_nsec != UTIME_OMIT)
|
||||||
// and the cache file does not exist.
|
// and the cache file does not exist.
|
||||||
// If mtime is specified for the file and the cache file
|
// If mtime is specified for the file and the cache file
|
||||||
// mtime is older than it, the cache file is removed and
|
// mtime is older than it, the cache file is removed and
|
||||||
// the processing comes here.
|
// the processing comes here.
|
||||||
//
|
//
|
||||||
pagelist.Resize(size, false, (UTIME_OMIT == ts_mctime.tv_nsec ? true : false));
|
pagelist.Resize(size, false, ts_times.IsOmitMTime());
|
||||||
|
|
||||||
is_truncate = true;
|
is_truncate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -570,14 +570,13 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts
|
|||||||
}else{
|
}else{
|
||||||
// [NOTE]
|
// [NOTE]
|
||||||
// The modify flag must not be set when opening a file,
|
// The modify flag must not be set when opening a file,
|
||||||
// if the ts_mctime parameter(mtime) is specified(tv_nsec != UTIME_OMIT)
|
// if the ts_times parameter(mtime) is specified(tv_nsec != UTIME_OMIT)
|
||||||
// and the cache file does not exist.
|
// and the cache file does not exist.
|
||||||
// If mtime is specified for the file and the cache file
|
// If mtime is specified for the file and the cache file
|
||||||
// mtime is older than it, the cache file is removed and
|
// mtime is older than it, the cache file is removed and
|
||||||
// the processing comes here.
|
// the processing comes here.
|
||||||
//
|
//
|
||||||
pagelist.Resize(size, false, (UTIME_OMIT == ts_mctime.tv_nsec ? true : false));
|
pagelist.Resize(size, false, ts_times.IsOmitMTime());
|
||||||
|
|
||||||
is_truncate = true;
|
is_truncate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -615,15 +614,13 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts
|
|||||||
truncated_size = size - size_orgmeta;
|
truncated_size = size - size_orgmeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set mtime and ctime(set "x-amz-meta-mtime" and "x-amz-meta-ctime" in orgmeta)
|
// set file timespecs(to internal varibales, cache file and original header)
|
||||||
if(UTIME_OMIT != ts_mctime.tv_nsec){
|
if(0 != (result = SetFileTimesHasLock(ts_times))){
|
||||||
if(0 != SetMCtimeHasLock(ts_mctime, ts_mctime)){
|
S3FS_PRN_ERR("failed to set file timespecs by result(%d)", result);
|
||||||
S3FS_PRN_ERR("failed to set mtime/ctime. errno(%d)", errno);
|
pfile.reset();
|
||||||
pfile.reset();
|
physical_fd = -1;
|
||||||
physical_fd = -1;
|
inode = 0;
|
||||||
inode = 0;
|
return result;
|
||||||
return (0 == errno ? -EIO : -errno);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,6 +752,10 @@ bool FdEntity::GetStatsHasLock(struct stat& st) const
|
|||||||
S3FS_PRN_ERR("fstat failed. errno(%d)", errno);
|
S3FS_PRN_ERR("fstat failed. errno(%d)", errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
||||||
|
timestamps.RefrectFileTimes(st);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,9 +763,10 @@ int FdEntity::SetCtimeHasLock(struct timespec time)
|
|||||||
{
|
{
|
||||||
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%s]", path.c_str(), physical_fd, str(time).c_str());
|
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%s]", path.c_str(), physical_fd, str(time).c_str());
|
||||||
|
|
||||||
if(-1 == time.tv_sec){
|
if(!valid_timespec(time)){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
timestamps.SetCTime(time);
|
||||||
orgmeta["x-amz-meta-ctime"] = str(time);
|
orgmeta["x-amz-meta-ctime"] = str(time);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -773,174 +775,82 @@ int FdEntity::SetAtimeHasLock(struct timespec time)
|
|||||||
{
|
{
|
||||||
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%s]", path.c_str(), physical_fd, str(time).c_str());
|
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%s]", path.c_str(), physical_fd, str(time).c_str());
|
||||||
|
|
||||||
if(-1 == time.tv_sec){
|
if(!valid_timespec(time)){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
timestamps.SetATime(time);
|
||||||
orgmeta["x-amz-meta-atime"] = str(time);
|
orgmeta["x-amz-meta-atime"] = str(time);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [NOTE]
|
int FdEntity::SetMtimeHasLock(struct timespec time)
|
||||||
// This method updates mtime as well as ctime.
|
|
||||||
//
|
|
||||||
int FdEntity::SetMCtimeHasLock(struct timespec mtime, struct timespec ctime)
|
|
||||||
{
|
{
|
||||||
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());
|
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][time=%s]", path.c_str(), physical_fd, str(time).c_str());
|
||||||
|
|
||||||
if(mtime.tv_sec < 0 || ctime.tv_sec < 0){
|
if(!valid_timespec(time)){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
timestamps.SetMTime(time);
|
||||||
if(-1 != physical_fd){
|
orgmeta["x-amz-meta-mtime"] = str(time);
|
||||||
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 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);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FdEntity::UpdateCtime()
|
// [NOTE]
|
||||||
|
// This method updates timespecs(atime/mtime) and origianl meta heders
|
||||||
|
//
|
||||||
|
int FdEntity::SetFileTimesHasLock(const FileTimes& ts_times)
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][ctime=%s,atime=%s,mtime=%s]", path.c_str(), physical_fd, str(ts_times.ctime()).c_str(), str(ts_times.atime()).c_str(), str(ts_times.mtime()).c_str());
|
||||||
struct stat st;
|
|
||||||
if(!GetStatsHasLock(st)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
orgmeta["x-amz-meta-ctime"] = str_stat_time(st, stat_time_type::CTIME);
|
// Set all timespecs without OMIT type
|
||||||
|
timestamps.SetAll(ts_times);
|
||||||
|
|
||||||
return true;
|
// Set timespecs(mtime/atime) to cache file
|
||||||
}
|
if(!timestamps.IsOmitATime() || !timestamps.IsOmitMTime()){
|
||||||
|
struct timespec ts[2];
|
||||||
|
ts[0] = timestamps.atime();
|
||||||
|
ts[1] = timestamps.mtime();
|
||||||
|
|
||||||
bool FdEntity::UpdateAtime()
|
if(-1 != physical_fd){
|
||||||
{
|
if(-1 == futimens(physical_fd, ts)){
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
S3FS_PRN_ERR("futimens failed. errno(%d)", errno);
|
||||||
struct stat st;
|
return -errno;
|
||||||
if(!GetStatsHasLock(st)){
|
}
|
||||||
return false;
|
}else{
|
||||||
}
|
if(-1 == utimensat(AT_FDCWD, cachepath.c_str(), ts, 0)){
|
||||||
|
S3FS_PRN_ERR("utimensat failed. errno(%d)", errno);
|
||||||
orgmeta["x-amz-meta-atime"] = str_stat_time(st, stat_time_type::ATIME);
|
return -errno;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FdEntity::UpdateMtime(bool clear_holding_mtime)
|
|
||||||
{
|
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
|
||||||
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
|
||||||
|
|
||||||
if(0 <= holding_mtime.tv_sec){
|
|
||||||
// [NOTE]
|
|
||||||
// This conditional statement is very special.
|
|
||||||
// If you copy a file with "cp -p" etc., utimens or chown will be
|
|
||||||
// called after opening the file, after that call to write, flush.
|
|
||||||
// If normally utimens are not called(cases like "cp" only), mtime
|
|
||||||
// should be updated at the file flush.
|
|
||||||
// Here, check the holding_mtime value to prevent mtime from being
|
|
||||||
// overwritten.
|
|
||||||
//
|
|
||||||
if(clear_holding_mtime){
|
|
||||||
if(!ClearHoldingMtime()){
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// [NOTE]
|
|
||||||
// If come here after fdatasync has been processed, the file
|
|
||||||
// content update has already taken place. However, the metadata
|
|
||||||
// update is necessary and needs to be flagged in order to
|
|
||||||
// perform it with flush,
|
|
||||||
//
|
|
||||||
pending_status = pending_status_t::UPDATE_META_PENDING;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set original meta headers / Set time to stat from original meta
|
||||||
|
if(!timestamps.IsOmitATime()){
|
||||||
|
orgmeta["x-amz-meta-atime"] = str(timestamps.atime());
|
||||||
}else{
|
}else{
|
||||||
struct stat st;
|
struct timespec meta_atime = get_atime(orgmeta, false);
|
||||||
if(!GetStatsHasLock(st)){
|
if(0 != meta_atime.tv_sec && UTIME_OMIT != meta_atime.tv_nsec){
|
||||||
return false;
|
timestamps.SetATime(meta_atime);
|
||||||
}
|
}
|
||||||
orgmeta["x-amz-meta-mtime"] = str_stat_time(st, stat_time_type::MTIME);
|
}
|
||||||
}
|
if(!timestamps.IsOmitMTime()){
|
||||||
return true;
|
orgmeta["x-amz-meta-mtime"] = str(timestamps.mtime());
|
||||||
}
|
}else{
|
||||||
|
struct timespec meta_mtime = get_mtime(orgmeta, false);
|
||||||
bool FdEntity::SetHoldingMtime(struct timespec mtime)
|
if(0 != meta_mtime.tv_sec && UTIME_OMIT != meta_mtime.tv_nsec){
|
||||||
{
|
timestamps.SetMTime(meta_mtime);
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
}
|
||||||
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
}
|
||||||
|
if(!timestamps.IsOmitCTime()){
|
||||||
S3FS_PRN_INFO3("[path=%s][physical_fd=%d][mtime=%s]", path.c_str(), physical_fd, str(mtime).c_str());
|
orgmeta["x-amz-meta-ctime"] = str(timestamps.ctime());
|
||||||
|
}else{
|
||||||
if(mtime.tv_sec < 0){
|
struct timespec meta_ctime = get_ctime(orgmeta, false);
|
||||||
return false;
|
if(0 != meta_ctime.tv_sec && UTIME_OMIT != meta_ctime.tv_nsec){
|
||||||
}
|
timestamps.SetCTime(meta_ctime);
|
||||||
holding_mtime = mtime;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FdEntity::ClearHoldingMtime()
|
|
||||||
{
|
|
||||||
if(holding_mtime.tv_sec < 0){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
struct stat st;
|
|
||||||
if(!GetStatsHasLock(st)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(-1 != physical_fd){
|
|
||||||
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, stat_time_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 timespec ts[2];
|
|
||||||
struct timespec ts_ctime;
|
|
||||||
|
|
||||||
set_stat_to_timespec(st, stat_time_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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
holding_mtime.tv_sec = -1;
|
|
||||||
holding_mtime.tv_nsec = 0;
|
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FdEntity::GetSize(off_t& size) const
|
bool FdEntity::GetSize(off_t& size) const
|
||||||
@ -1015,6 +925,8 @@ bool FdEntity::GetStatsFromMeta(struct stat& st) const
|
|||||||
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
||||||
st.st_size = pagelist.Size(); // set current file size
|
st.st_size = pagelist.Size(); // set current file size
|
||||||
|
|
||||||
|
timestamps.RefrectFileTimes(st);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2459,6 +2371,7 @@ bool FdEntity::MergeOrgMeta(headers_t& updatemeta)
|
|||||||
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
const std::lock_guard<std::mutex> data_lock(fdent_data_lock);
|
||||||
|
|
||||||
merge_headers(orgmeta, updatemeta, true); // overwrite all keys
|
merge_headers(orgmeta, updatemeta, true); // overwrite all keys
|
||||||
|
|
||||||
// [NOTE]
|
// [NOTE]
|
||||||
// this is special cases, we remove the key which has empty values.
|
// this is special cases, we remove the key which has empty values.
|
||||||
for(auto hiter = orgmeta.cbegin(); hiter != orgmeta.cend(); ){
|
for(auto hiter = orgmeta.cbegin(); hiter != orgmeta.cend(); ){
|
||||||
@ -2475,12 +2388,8 @@ bool FdEntity::MergeOrgMeta(headers_t& updatemeta)
|
|||||||
struct timespec mtime = get_mtime(updatemeta, false); // not overcheck
|
struct timespec mtime = get_mtime(updatemeta, false); // not overcheck
|
||||||
struct timespec ctime = get_ctime(updatemeta, false); // not overcheck
|
struct timespec ctime = get_ctime(updatemeta, false); // not overcheck
|
||||||
struct timespec atime = get_atime(updatemeta, false); // not overcheck
|
struct timespec atime = get_atime(updatemeta, false); // not overcheck
|
||||||
if(0 <= mtime.tv_sec){
|
|
||||||
SetMCtimeHasLock(mtime, (ctime.tv_sec < 0 ? mtime : ctime));
|
timestamps.SetAll(ctime, atime, mtime); // set all timespecs to internal data
|
||||||
}
|
|
||||||
if(0 <= atime.tv_sec){
|
|
||||||
SetAtimeHasLock(atime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pending_status_t::NO_UPDATE_PENDING == pending_status && (IsUploading() || pagelist.IsModified())){
|
if(pending_status_t::NO_UPDATE_PENDING == pending_status && (IsUploading() || pagelist.IsModified())){
|
||||||
pending_status = pending_status_t::UPDATE_META_PENDING;
|
pending_status = pending_status_t::UPDATE_META_PENDING;
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
#include "fdcache_untreated.h"
|
#include "fdcache_untreated.h"
|
||||||
#include "metaheader.h"
|
#include "metaheader.h"
|
||||||
#include "s3fs_util.h"
|
#include "s3fs_util.h"
|
||||||
|
#include "filetimes.h"
|
||||||
|
|
||||||
//----------------------------------------------
|
//----------------------------------------------
|
||||||
// Typedef
|
// Typedef
|
||||||
@ -60,25 +61,24 @@ class FdEntity : public std::enable_shared_from_this<FdEntity>
|
|||||||
static bool streamupload; // whether stream uploading.
|
static bool streamupload; // whether stream uploading.
|
||||||
|
|
||||||
mutable std::mutex fdent_lock;
|
mutable std::mutex fdent_lock;
|
||||||
std::string path GUARDED_BY(fdent_lock); // object path
|
std::string path GUARDED_BY(fdent_lock); // object path
|
||||||
int physical_fd GUARDED_BY(fdent_lock); // physical file(cache or temporary file) descriptor
|
int physical_fd GUARDED_BY(fdent_lock); // physical file(cache or temporary file) descriptor
|
||||||
UntreatedParts untreated_list GUARDED_BY(fdent_lock); // list of untreated parts that have been written and not yet uploaded(for streamupload)
|
UntreatedParts untreated_list GUARDED_BY(fdent_lock); // list of untreated parts that have been written and not yet uploaded(for streamupload)
|
||||||
fdinfo_map_t pseudo_fd_map GUARDED_BY(fdent_lock); // pseudo file descriptor information map
|
fdinfo_map_t pseudo_fd_map GUARDED_BY(fdent_lock); // pseudo file descriptor information map
|
||||||
std::unique_ptr<FILE, decltype(&s3fs_fclose)> pfile GUARDED_BY(fdent_lock) = {nullptr, &s3fs_fclose}; // file pointer(tmp file or cache file)
|
std::unique_ptr<FILE, decltype(&s3fs_fclose)> pfile GUARDED_BY(fdent_lock) = {nullptr, &s3fs_fclose}; // file pointer(tmp file or cache file)
|
||||||
ino_t inode GUARDED_BY(fdent_lock); // inode number for cache file
|
ino_t inode GUARDED_BY(fdent_lock); // inode number for cache file
|
||||||
headers_t orgmeta GUARDED_BY(fdent_lock); // original headers at opening
|
headers_t orgmeta GUARDED_BY(fdent_lock); // original headers at opening
|
||||||
off_t size_orgmeta GUARDED_BY(fdent_lock); // original file size in original headers
|
off_t size_orgmeta GUARDED_BY(fdent_lock); // original file size in original headers
|
||||||
|
|
||||||
mutable std::mutex fdent_data_lock ACQUIRED_AFTER(fdent_lock);// protects the following members
|
mutable std::mutex fdent_data_lock ACQUIRED_AFTER(fdent_lock); // protects the following members
|
||||||
PageList pagelist GUARDED_BY(fdent_data_lock);
|
PageList pagelist GUARDED_BY(fdent_data_lock);
|
||||||
std::string cachepath GUARDED_BY(fdent_data_lock); // local cache file path
|
std::string cachepath GUARDED_BY(fdent_data_lock); // local cache file path
|
||||||
// (if this is empty, does not load/save pagelist.)
|
// (if this is empty, does not load/save pagelist.)
|
||||||
std::string mirrorpath GUARDED_BY(fdent_data_lock); // mirror file path to local cache file path
|
std::string mirrorpath GUARDED_BY(fdent_data_lock); // mirror file path to local cache file path
|
||||||
pending_status_t pending_status GUARDED_BY(fdent_data_lock); // status for new file creation and meta update
|
pending_status_t pending_status GUARDED_BY(fdent_data_lock); // status for new file creation and meta update
|
||||||
struct timespec holding_mtime GUARDED_BY(fdent_data_lock); // if mtime is updated while the file is open, it is set time_t value
|
FileTimes timestamps GUARDED_BY(fdent_data_lock); // file timestamps(atime/ctime/mtime)
|
||||||
|
mutable std::mutex ro_path_lock; // for only the ro_path variable
|
||||||
mutable std::mutex ro_path_lock; // for only the ro_path variable
|
std::string ro_path GUARDED_BY(ro_path_lock); // holds the same value as "path". this is used as a backup(read-only variable) by special functions only.
|
||||||
std::string ro_path GUARDED_BY(ro_path_lock); // holds the same value as "path". this is used as a backup(read-only variable) by special functions only.
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int FillFile(int fd, unsigned char byte, off_t size, off_t start);
|
static int FillFile(int fd, unsigned char byte, off_t size, off_t start);
|
||||||
@ -90,6 +90,10 @@ class FdEntity : public std::enable_shared_from_this<FdEntity>
|
|||||||
int NoCacheLoadAndPost(PseudoFdInfo* pseudo_obj, off_t start = 0, off_t size = 0) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock); // size=0 means loading to end
|
int NoCacheLoadAndPost(PseudoFdInfo* pseudo_obj, off_t start = 0, off_t size = 0) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock); // size=0 means loading to end
|
||||||
PseudoFdInfo* CheckPseudoFdFlags(int fd, bool writable) REQUIRES(FdEntity::fdent_lock);
|
PseudoFdInfo* CheckPseudoFdFlags(int fd, bool writable) REQUIRES(FdEntity::fdent_lock);
|
||||||
bool IsUploading() REQUIRES(FdEntity::fdent_lock);
|
bool IsUploading() REQUIRES(FdEntity::fdent_lock);
|
||||||
|
int SetCtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
||||||
|
int SetAtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
||||||
|
int SetMtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
||||||
|
int SetFileTimesHasLock(const FileTimes& ts_times) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
||||||
bool SetAllStatus(bool is_loaded) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
bool SetAllStatus(bool is_loaded) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
||||||
bool SetAllStatusUnloaded() REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock) { return SetAllStatus(false); }
|
bool SetAllStatusUnloaded() REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock) { return SetAllStatus(false); }
|
||||||
int PreMultipartUploadRequest(PseudoFdInfo* pseudo_obj) REQUIRES(FdEntity::fdent_lock, fdent_data_lock);
|
int PreMultipartUploadRequest(PseudoFdInfo* pseudo_obj) REQUIRES(FdEntity::fdent_lock, fdent_data_lock);
|
||||||
@ -143,7 +147,8 @@ class FdEntity : public std::enable_shared_from_this<FdEntity>
|
|||||||
const std::lock_guard<std::mutex> ro_lock(ro_path_lock);
|
const std::lock_guard<std::mutex> ro_lock(ro_path_lock);
|
||||||
return ro_path;
|
return ro_path;
|
||||||
}
|
}
|
||||||
int Open(const headers_t* pmeta, off_t size, const struct timespec& ts_mctime, int flags);
|
int Open(const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags);
|
||||||
|
|
||||||
bool LoadAll(int fd, off_t* size = nullptr, bool force_load = false);
|
bool LoadAll(int fd, off_t* size = nullptr, bool force_load = false);
|
||||||
int Dup(int fd) {
|
int Dup(int fd) {
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
const std::lock_guard<std::mutex> lock(fdent_lock);
|
||||||
@ -182,28 +187,23 @@ class FdEntity : public std::enable_shared_from_this<FdEntity>
|
|||||||
return GetStatsHasLock(st);
|
return GetStatsHasLock(st);
|
||||||
}
|
}
|
||||||
bool GetStatsHasLock(struct stat& st) const REQUIRES(FdEntity::fdent_lock);
|
bool GetStatsHasLock(struct stat& st) const REQUIRES(FdEntity::fdent_lock);
|
||||||
|
|
||||||
int SetCtime(struct timespec time) {
|
int SetCtime(struct timespec time) {
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
const std::lock_guard<std::mutex> lock(fdent_lock);
|
||||||
return SetCtimeHasLock(time);
|
const std::lock_guard<std::mutex> lock2(fdent_data_lock);
|
||||||
|
return SetCtimeHasLock(time);
|
||||||
}
|
}
|
||||||
int SetCtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock);
|
|
||||||
int SetAtime(struct timespec time) {
|
int SetAtime(struct timespec time) {
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
const std::lock_guard<std::mutex> lock(fdent_lock);
|
||||||
return SetAtimeHasLock(time);
|
const std::lock_guard<std::mutex> lock2(fdent_data_lock);
|
||||||
|
return SetAtimeHasLock(time);
|
||||||
}
|
}
|
||||||
int SetAtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock);
|
int SetMtime(struct timespec time) {
|
||||||
int SetMCtime(struct timespec mtime, struct timespec ctime) {
|
const std::lock_guard<std::mutex> lock(fdent_lock);
|
||||||
const std::lock_guard<std::mutex> lock(fdent_lock);
|
const std::lock_guard<std::mutex> lock2(fdent_data_lock);
|
||||||
const std::lock_guard<std::mutex> lock2(fdent_data_lock);
|
return SetMtimeHasLock(time);
|
||||||
return SetMCtimeHasLock(mtime, ctime);
|
|
||||||
}
|
}
|
||||||
int SetMCtimeHasLock(struct timespec mtime, struct timespec ctime) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
|
||||||
bool UpdateCtime();
|
|
||||||
bool UpdateAtime();
|
|
||||||
bool UpdateMtime(bool clear_holding_mtime = false);
|
|
||||||
bool UpdateMCtime();
|
|
||||||
bool SetHoldingMtime(struct timespec mtime);
|
|
||||||
bool ClearHoldingMtime() REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
|
|
||||||
bool GetSize(off_t& size) const;
|
bool GetSize(off_t& size) const;
|
||||||
bool GetXattr(std::string& xattr) const;
|
bool GetXattr(std::string& xattr) const;
|
||||||
bool SetXattr(const std::string& xattr);
|
bool SetXattr(const std::string& xattr);
|
||||||
|
|||||||
303
src/filetimes.cpp
Normal file
303
src/filetimes.cpp
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/*
|
||||||
|
* s3fs - FUSE-based file system backed by Amazon S3
|
||||||
|
*
|
||||||
|
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "filetimes.h"
|
||||||
|
#include "s3fs_logger.h"
|
||||||
|
#include "string_util.h"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// Utility functions
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// result: -1 ts1 < ts2
|
||||||
|
// 0 ts1 == ts2
|
||||||
|
// 1 ts1 > ts2
|
||||||
|
//
|
||||||
|
bool valid_timespec(const struct timespec& ts)
|
||||||
|
{
|
||||||
|
if(0 > ts.tv_sec || UTIME_OMIT == ts.tv_nsec || UTIME_NOW == ts.tv_nsec){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// result: -1 ts1 < ts2
|
||||||
|
// 0 ts1 == ts2
|
||||||
|
// 1 ts1 > ts2
|
||||||
|
//
|
||||||
|
constexpr 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(stat_time_type::ATIME == type){
|
||||||
|
#ifdef __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(stat_time_type::MTIME == type){
|
||||||
|
#ifdef __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(stat_time_type::CTIME == type){
|
||||||
|
#ifdef __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.", static_cast<int>(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timespec* set_stat_to_timespec(const struct stat& st, stat_time_type type, struct timespec& ts)
|
||||||
|
{
|
||||||
|
if(stat_time_type::ATIME == type){
|
||||||
|
#ifdef __APPLE__
|
||||||
|
ts.tv_sec = st.st_atime;
|
||||||
|
ts.tv_nsec = st.st_atimespec.tv_nsec;
|
||||||
|
#else
|
||||||
|
ts = st.st_atim;
|
||||||
|
#endif
|
||||||
|
}else if(stat_time_type::MTIME == type){
|
||||||
|
#ifdef __APPLE__
|
||||||
|
ts.tv_sec = st.st_mtime;
|
||||||
|
ts.tv_nsec = st.st_mtimespec.tv_nsec;
|
||||||
|
#else
|
||||||
|
ts = st.st_mtim;
|
||||||
|
#endif
|
||||||
|
}else if(stat_time_type::CTIME == type){
|
||||||
|
#ifdef __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.", static_cast<int>(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(nullptr);
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
}
|
||||||
|
return &ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string s3fs_str_realtime()
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
return str(*s3fs_realtime(ts));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// FileTimes Class
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
void FileTimes::Clear()
|
||||||
|
{
|
||||||
|
ClearCTime();
|
||||||
|
ClearATime();
|
||||||
|
ClearMTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::Clear(stat_time_type type)
|
||||||
|
{
|
||||||
|
if(stat_time_type::CTIME == type){
|
||||||
|
ft_ctime = {0, UTIME_OMIT};
|
||||||
|
}else if(stat_time_type::ATIME == type){
|
||||||
|
ft_atime = {0, UTIME_OMIT};
|
||||||
|
}else{ // stat_time_type::MTIME
|
||||||
|
ft_mtime = {0, UTIME_OMIT};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct timespec& FileTimes::GetTime(stat_time_type type) const
|
||||||
|
{
|
||||||
|
if(stat_time_type::CTIME == type){
|
||||||
|
return ft_ctime;
|
||||||
|
}else if(stat_time_type::ATIME == type){
|
||||||
|
return ft_atime;
|
||||||
|
}else{ // stat_time_type::MTIME
|
||||||
|
return ft_mtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::GetTime(stat_time_type type, struct timespec& time) const
|
||||||
|
{
|
||||||
|
if(stat_time_type::CTIME == type){
|
||||||
|
time = ft_ctime;
|
||||||
|
}else if(stat_time_type::ATIME == type){
|
||||||
|
time = ft_atime;
|
||||||
|
}else{ // stat_time_type::MTIME
|
||||||
|
time = ft_mtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::RefrectFileTimes(struct stat& st) const
|
||||||
|
{
|
||||||
|
if(!IsOmitCTime()){
|
||||||
|
set_timespec_to_stat(st, stat_time_type::CTIME, ft_ctime);
|
||||||
|
}
|
||||||
|
if(!IsOmitATime()){
|
||||||
|
set_timespec_to_stat(st, stat_time_type::ATIME, ft_atime);
|
||||||
|
}
|
||||||
|
if(!IsOmitMTime()){
|
||||||
|
set_timespec_to_stat(st, stat_time_type::MTIME, ft_mtime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::SetTime(stat_time_type type, struct timespec time)
|
||||||
|
{
|
||||||
|
if(UTIME_NOW == time.tv_nsec){
|
||||||
|
s3fs_realtime(time);
|
||||||
|
}
|
||||||
|
if(stat_time_type::CTIME == type){
|
||||||
|
ft_ctime = time;
|
||||||
|
}else if(stat_time_type::ATIME == type){
|
||||||
|
ft_atime = time;
|
||||||
|
}else{ // stat_time_type::MTIME
|
||||||
|
ft_mtime = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::SetAllNow()
|
||||||
|
{
|
||||||
|
struct timespec time;
|
||||||
|
s3fs_realtime(time);
|
||||||
|
SetAll(time, time, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::SetAll(const struct stat& stbuf, bool no_omit)
|
||||||
|
{
|
||||||
|
struct timespec ts_ctime;
|
||||||
|
struct timespec ts_atime;
|
||||||
|
struct timespec ts_mtime;
|
||||||
|
set_stat_to_timespec(stbuf, stat_time_type::CTIME, ts_ctime);
|
||||||
|
set_stat_to_timespec(stbuf, stat_time_type::ATIME, ts_atime);
|
||||||
|
set_stat_to_timespec(stbuf, stat_time_type::MTIME, ts_mtime);
|
||||||
|
|
||||||
|
SetAll(ts_ctime, ts_atime, ts_mtime, no_omit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::SetAll(struct timespec ts_ctime, struct timespec ts_atime, struct timespec ts_mtime, bool no_omit)
|
||||||
|
{
|
||||||
|
struct timespec ts_now_time;
|
||||||
|
s3fs_realtime(ts_now_time);
|
||||||
|
|
||||||
|
if(UTIME_NOW == ts_ctime.tv_nsec){
|
||||||
|
SetCTime(ts_now_time);
|
||||||
|
}else if(!no_omit || UTIME_OMIT != ts_ctime.tv_nsec){
|
||||||
|
SetCTime(ts_ctime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(UTIME_NOW == ts_atime.tv_nsec){
|
||||||
|
SetATime(ts_now_time);
|
||||||
|
}else if(!no_omit || UTIME_OMIT != ts_atime.tv_nsec){
|
||||||
|
SetATime(ts_atime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(UTIME_NOW == ts_mtime.tv_nsec){
|
||||||
|
SetMTime(ts_now_time);
|
||||||
|
}else if(!no_omit || UTIME_OMIT != ts_mtime.tv_nsec){
|
||||||
|
SetMTime(ts_mtime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTimes::SetAll(const FileTimes& other, bool no_omit)
|
||||||
|
{
|
||||||
|
if(!no_omit || !other.IsOmitCTime()){
|
||||||
|
SetCTime(other.ctime());
|
||||||
|
}
|
||||||
|
if(!no_omit || !other.IsOmitATime()){
|
||||||
|
SetATime(other.atime());
|
||||||
|
}
|
||||||
|
if(!no_omit || !other.IsOmitMTime()){
|
||||||
|
SetMTime(other.mtime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileTimes::IsOmit(stat_time_type type) const
|
||||||
|
{
|
||||||
|
if(stat_time_type::CTIME == type){
|
||||||
|
return (UTIME_OMIT == ft_ctime.tv_nsec);
|
||||||
|
}else if(stat_time_type::ATIME == type){
|
||||||
|
return (UTIME_OMIT == ft_atime.tv_nsec);
|
||||||
|
}else{ // stat_time_type::MTIME
|
||||||
|
return (UTIME_OMIT == ft_mtime.tv_nsec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* tab-width: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* End:
|
||||||
|
* vim600: expandtab sw=4 ts=4 fdm=marker
|
||||||
|
* vim<600: expandtab sw=4 ts=4
|
||||||
|
*/
|
||||||
120
src/filetimes.h
Normal file
120
src/filetimes.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* s3fs - FUSE-based file system backed by Amazon S3
|
||||||
|
*
|
||||||
|
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef S3FS_FILETIMES_H_
|
||||||
|
#define S3FS_FILETIMES_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// Utility for stat time type
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
enum class stat_time_type : uint8_t {
|
||||||
|
ATIME,
|
||||||
|
MTIME,
|
||||||
|
CTIME
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// Utility Functions for timespecs
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
bool valid_timespec(const struct timespec& ts);
|
||||||
|
constexpr 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();
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// FileTimes Class
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// [NOTE]
|
||||||
|
// In this class, UTIME_OMIT is set when initializing or clearing
|
||||||
|
// internal data.
|
||||||
|
// Also, if UTIME_NOW is specified, the value will be corrected to
|
||||||
|
// the current time and maintained.
|
||||||
|
//
|
||||||
|
class FileTimes
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct timespec ft_ctime; // Change time
|
||||||
|
struct timespec ft_atime; // Access time
|
||||||
|
struct timespec ft_mtime; // Modification time
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Clear(stat_time_type type);
|
||||||
|
|
||||||
|
const struct timespec& GetTime(stat_time_type type) const;
|
||||||
|
void GetTime(stat_time_type type, struct timespec& time) const;
|
||||||
|
|
||||||
|
void SetTime(stat_time_type type, struct timespec time);
|
||||||
|
|
||||||
|
bool IsOmit(stat_time_type type) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FileTimes() : ft_ctime{0, UTIME_OMIT}, ft_atime{0, UTIME_OMIT}, ft_mtime{0, UTIME_OMIT} {}
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
void Clear();
|
||||||
|
void ClearCTime() { Clear(stat_time_type::CTIME); }
|
||||||
|
void ClearATime() { Clear(stat_time_type::ATIME); }
|
||||||
|
void ClearMTime() { Clear(stat_time_type::MTIME); }
|
||||||
|
|
||||||
|
// Get value
|
||||||
|
const struct timespec& ctime() const { return GetTime(stat_time_type::CTIME); }
|
||||||
|
const struct timespec& atime() const { return GetTime(stat_time_type::ATIME); }
|
||||||
|
const struct timespec& mtime() const { return GetTime(stat_time_type::MTIME); }
|
||||||
|
|
||||||
|
void GetCTime(struct timespec& time) const { GetTime(stat_time_type::CTIME, time); }
|
||||||
|
void GetATime(struct timespec& time) const { GetTime(stat_time_type::ATIME, time); }
|
||||||
|
void GetMTime(struct timespec& time) const { GetTime(stat_time_type::MTIME, time); }
|
||||||
|
|
||||||
|
void RefrectFileTimes(struct stat& st) const;
|
||||||
|
|
||||||
|
// Set value
|
||||||
|
void SetCTime(struct timespec time) { SetTime(stat_time_type::CTIME, time); }
|
||||||
|
void SetATime(struct timespec time) { SetTime(stat_time_type::ATIME, time); }
|
||||||
|
void SetMTime(struct timespec time) { SetTime(stat_time_type::MTIME, time); }
|
||||||
|
|
||||||
|
void SetAllNow();
|
||||||
|
void SetAll(const struct stat& stbuf, bool no_omit = true);
|
||||||
|
void SetAll(struct timespec ts_ctime, struct timespec ts_atime, struct timespec ts_mtime, bool no_omit = true);
|
||||||
|
void SetAll(const FileTimes& other, bool no_omit = true);
|
||||||
|
|
||||||
|
// Check
|
||||||
|
bool IsOmitCTime() const { return IsOmit(stat_time_type::CTIME); }
|
||||||
|
bool IsOmitATime() const { return IsOmit(stat_time_type::ATIME); }
|
||||||
|
bool IsOmitMTime() const { return IsOmit(stat_time_type::MTIME); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // S3FS_FILETIMES_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* tab-width: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* End:
|
||||||
|
* vim600: expandtab sw=4 ts=4 fdm=marker
|
||||||
|
* vim<600: expandtab sw=4 ts=4
|
||||||
|
*/
|
||||||
@ -27,8 +27,10 @@
|
|||||||
#include "metaheader.h"
|
#include "metaheader.h"
|
||||||
#include "string_util.h"
|
#include "string_util.h"
|
||||||
#include "s3fs_util.h"
|
#include "s3fs_util.h"
|
||||||
|
#include "filetimes.h"
|
||||||
|
|
||||||
static constexpr struct timespec DEFAULT_TIMESPEC = {-1, 0};
|
static constexpr struct timespec ERROR_TIMESPEC = {-1, 0};
|
||||||
|
static constexpr struct timespec OMIT_TIMESPEC = {0, UTIME_OMIT};
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Utility functions for convert
|
// Utility functions for convert
|
||||||
@ -59,52 +61,53 @@ static struct timespec get_time(const headers_t& meta, const char *header)
|
|||||||
{
|
{
|
||||||
headers_t::const_iterator iter;
|
headers_t::const_iterator iter;
|
||||||
if(meta.cend() == (iter = meta.find(header))){
|
if(meta.cend() == (iter = meta.find(header))){
|
||||||
return DEFAULT_TIMESPEC;
|
return ERROR_TIMESPEC;
|
||||||
}
|
}
|
||||||
return cvt_string_to_time((*iter).second.c_str());
|
return cvt_string_to_time((*iter).second.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec get_mtime(const headers_t& meta, bool overcheck)
|
struct timespec get_mtime(const headers_t& meta, bool overcheck)
|
||||||
{
|
{
|
||||||
struct timespec t = get_time(meta, "x-amz-meta-mtime");
|
struct timespec mtime = get_time(meta, "x-amz-meta-mtime");
|
||||||
if(0 < t.tv_sec){
|
if(0 <= mtime.tv_sec && UTIME_OMIT != mtime.tv_nsec){
|
||||||
return t;
|
return mtime;
|
||||||
}
|
}
|
||||||
t = get_time(meta, "x-amz-meta-goog-reserved-file-mtime");
|
|
||||||
if(0 < t.tv_sec){
|
mtime = get_time(meta, "x-amz-meta-goog-reserved-file-mtime");
|
||||||
return t;
|
if(0 <= mtime.tv_sec && UTIME_OMIT != mtime.tv_nsec){
|
||||||
|
return mtime;
|
||||||
}
|
}
|
||||||
if(overcheck){
|
if(overcheck){
|
||||||
struct timespec ts = {get_lastmodified(meta), 0};
|
mtime = {get_lastmodified(meta), 0};
|
||||||
return ts;
|
return mtime;
|
||||||
}
|
}
|
||||||
return DEFAULT_TIMESPEC;
|
return OMIT_TIMESPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec get_ctime(const headers_t& meta, bool overcheck)
|
struct timespec get_ctime(const headers_t& meta, bool overcheck)
|
||||||
{
|
{
|
||||||
struct timespec t = get_time(meta, "x-amz-meta-ctime");
|
struct timespec ctime = get_time(meta, "x-amz-meta-ctime");
|
||||||
if(0 < t.tv_sec){
|
if(0 <= ctime.tv_sec && UTIME_OMIT != ctime.tv_nsec){
|
||||||
return t;
|
return ctime;
|
||||||
}
|
}
|
||||||
if(overcheck){
|
if(overcheck){
|
||||||
struct timespec ts = {get_lastmodified(meta), 0};
|
ctime = {get_lastmodified(meta), 0};
|
||||||
return ts;
|
return ctime;
|
||||||
}
|
}
|
||||||
return DEFAULT_TIMESPEC;
|
return OMIT_TIMESPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec get_atime(const headers_t& meta, bool overcheck)
|
struct timespec get_atime(const headers_t& meta, bool overcheck)
|
||||||
{
|
{
|
||||||
struct timespec t = get_time(meta, "x-amz-meta-atime");
|
struct timespec atime = get_time(meta, "x-amz-meta-atime");
|
||||||
if(0 < t.tv_sec){
|
if(0 <= atime.tv_sec && UTIME_OMIT != atime.tv_nsec){
|
||||||
return t;
|
return atime;
|
||||||
}
|
}
|
||||||
if(overcheck){
|
if(overcheck){
|
||||||
struct timespec ts = {get_lastmodified(meta), 0};
|
atime = {get_lastmodified(meta), 0};
|
||||||
return ts;
|
return atime;
|
||||||
}
|
}
|
||||||
return DEFAULT_TIMESPEC;
|
return OMIT_TIMESPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t get_size(const char *s)
|
off_t get_size(const char *s)
|
||||||
@ -447,39 +450,24 @@ bool convert_header_to_stat(const std::string& strpath, const headers_t& meta, s
|
|||||||
|
|
||||||
// mtime
|
// mtime
|
||||||
struct timespec mtime = get_mtime(meta);
|
struct timespec mtime = get_mtime(meta);
|
||||||
if(stbuf.st_mtime < 0){
|
if(mtime.tv_sec < 0){
|
||||||
stbuf.st_mtime = 0L;
|
mtime = {0, 0};
|
||||||
}else{
|
|
||||||
if(mtime.tv_sec < 0){
|
|
||||||
mtime.tv_sec = 0;
|
|
||||||
mtime.tv_nsec = 0;
|
|
||||||
}
|
|
||||||
set_timespec_to_stat(stbuf, stat_time_type::MTIME, mtime);
|
|
||||||
}
|
}
|
||||||
|
set_timespec_to_stat(stbuf, stat_time_type::MTIME, mtime);
|
||||||
|
|
||||||
// ctime
|
// ctime
|
||||||
struct timespec ctime = get_ctime(meta);
|
struct timespec ctime = get_ctime(meta);
|
||||||
if(stbuf.st_ctime < 0){
|
if(ctime.tv_sec < 0){
|
||||||
stbuf.st_ctime = 0L;
|
ctime = {0, 0};
|
||||||
}else{
|
|
||||||
if(ctime.tv_sec < 0){
|
|
||||||
ctime.tv_sec = 0;
|
|
||||||
ctime.tv_nsec = 0;
|
|
||||||
}
|
|
||||||
set_timespec_to_stat(stbuf, stat_time_type::CTIME, ctime);
|
|
||||||
}
|
}
|
||||||
|
set_timespec_to_stat(stbuf, stat_time_type::CTIME, ctime);
|
||||||
|
|
||||||
// atime
|
// atime
|
||||||
struct timespec atime = get_atime(meta);
|
struct timespec atime = get_atime(meta);
|
||||||
if(stbuf.st_atime < 0){
|
if(atime.tv_sec < 0){
|
||||||
stbuf.st_atime = 0L;
|
atime = {0, 0};
|
||||||
}else{
|
|
||||||
if(atime.tv_sec < 0){
|
|
||||||
atime.tv_sec = 0;
|
|
||||||
atime.tv_nsec = 0;
|
|
||||||
}
|
|
||||||
set_timespec_to_stat(stbuf, stat_time_type::ATIME, atime);
|
|
||||||
}
|
}
|
||||||
|
set_timespec_to_stat(stbuf, stat_time_type::ATIME, atime);
|
||||||
|
|
||||||
// size
|
// size
|
||||||
if(S_ISDIR(stbuf.st_mode)){
|
if(S_ISDIR(stbuf.st_mode)){
|
||||||
|
|||||||
131
src/s3fs.cpp
131
src/s3fs.cpp
@ -825,6 +825,7 @@ static int get_local_fent(AutoFdEntity& autoent, FdEntity **entity, const char*
|
|||||||
struct stat stobj;
|
struct stat stobj;
|
||||||
FdEntity* ent;
|
FdEntity* ent;
|
||||||
headers_t meta;
|
headers_t meta;
|
||||||
|
FileTimes ts_times; // default: all timespecs are UTIME_OMIT
|
||||||
|
|
||||||
S3FS_PRN_INFO2("[path=%s]", path);
|
S3FS_PRN_INFO2("[path=%s]", path);
|
||||||
|
|
||||||
@ -833,15 +834,12 @@ static int get_local_fent(AutoFdEntity& autoent, FdEntity **entity, const char*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// open
|
// open
|
||||||
struct timespec st_mctime;
|
if(S_ISREG(stobj.st_mode) || S_ISLNK(stobj.st_mode)){
|
||||||
if(!S_ISREG(stobj.st_mode) && !S_ISLNK(stobj.st_mode)){
|
ts_times.SetAll(stobj);
|
||||||
st_mctime = S3FS_OMIT_TS;
|
|
||||||
}else{
|
|
||||||
set_stat_to_timespec(stobj, stat_time_type::MTIME, st_mctime);
|
|
||||||
}
|
}
|
||||||
bool force_tmpfile = S_ISREG(stobj.st_mode) ? false : true;
|
bool force_tmpfile = S_ISREG(stobj.st_mode) ? false : true;
|
||||||
|
|
||||||
if(nullptr == (ent = autoent.Open(path, &meta, stobj.st_size, st_mctime, flags, force_tmpfile, true, false))){
|
if(nullptr == (ent = autoent.Open(path, &meta, stobj.st_size, ts_times, flags, force_tmpfile, true, false))){
|
||||||
S3FS_PRN_ERR("Could not open file. errno(%d)", errno);
|
S3FS_PRN_ERR("Could not open file. errno(%d)", errno);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@ -1173,8 +1171,9 @@ static int s3fs_create(const char* _path, mode_t mode, struct fuse_file_info* fi
|
|||||||
|
|
||||||
AutoFdEntity autoent;
|
AutoFdEntity autoent;
|
||||||
FdEntity* ent;
|
FdEntity* ent;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
if(nullptr == (ent = autoent.Open(strpath.c_str(), &meta, 0, S3FS_OMIT_TS, fi->flags, false, true, false, &error))){
|
FileTimes ts_times;
|
||||||
|
if(nullptr == (ent = autoent.Open(strpath.c_str(), &meta, 0, ts_times, fi->flags, false, true, false, &error))){
|
||||||
// remove from cache
|
// remove from cache
|
||||||
StatCache::getStatCacheData()->DelStat(strpath);
|
StatCache::getStatCacheData()->DelStat(strpath);
|
||||||
return error;
|
return error;
|
||||||
@ -1447,10 +1446,12 @@ static int s3fs_symlink(const char* _from, const char* _to)
|
|||||||
{ // scope for AutoFdEntity
|
{ // scope for AutoFdEntity
|
||||||
AutoFdEntity autoent;
|
AutoFdEntity autoent;
|
||||||
FdEntity* ent;
|
FdEntity* ent;
|
||||||
if(nullptr == (ent = autoent.Open(strTo.c_str(), &headers, 0, S3FS_OMIT_TS, O_RDWR, true, true, false))){
|
FileTimes ts_times; // Default: all time values are set UTIME_OMIT
|
||||||
|
if(nullptr == (ent = autoent.Open(strTo.c_str(), &headers, 0, ts_times, O_RDWR, true, true, false))){
|
||||||
S3FS_PRN_ERR("could not open tmpfile(errno=%d)", errno);
|
S3FS_PRN_ERR("could not open tmpfile(errno=%d)", errno);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write(without space words)
|
// write(without space words)
|
||||||
auto from_size = static_cast<ssize_t>(strFrom.length());
|
auto from_size = static_cast<ssize_t>(strFrom.length());
|
||||||
ssize_t ressize;
|
ssize_t ressize;
|
||||||
@ -1543,38 +1544,28 @@ static int rename_object(const char* from, const char* to, bool update_ctime)
|
|||||||
struct timespec mtime = get_mtime(meta);
|
struct timespec mtime = get_mtime(meta);
|
||||||
struct timespec ctime = get_ctime(meta);
|
struct timespec ctime = get_ctime(meta);
|
||||||
struct timespec atime = get_atime(meta);
|
struct timespec atime = get_atime(meta);
|
||||||
if(mtime.tv_sec < 0){
|
|
||||||
mtime.tv_sec = 0L;
|
|
||||||
mtime.tv_nsec = 0L;
|
|
||||||
}
|
|
||||||
if(ctime.tv_sec < 0){
|
|
||||||
ctime.tv_sec = 0L;
|
|
||||||
ctime.tv_nsec = 0L;
|
|
||||||
}
|
|
||||||
if(atime.tv_sec < 0){
|
|
||||||
atime.tv_sec = 0L;
|
|
||||||
atime.tv_nsec = 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(FdManager::IsCacheDir()){
|
if(FdManager::IsCacheDir()){
|
||||||
// create cache file if be needed
|
// create cache file if be needed
|
||||||
//
|
//
|
||||||
// [NOTE]
|
// [NOTE]
|
||||||
// Do not specify "S3FS_OMIT_TS" for mctime parameter.
|
// Do not specify "UTIME_OMIT" for ts_time parameter.
|
||||||
// This is because if the cache file does not exist, the pagelist for it
|
// This is because if the cache file does not exist, the pagelist for it
|
||||||
// will be recreated, but the entire file area indicated by this pagelist
|
// will be recreated, but the entire file area indicated by this pagelist
|
||||||
// will be in the "modified" state.
|
// will be in the "modified" state.
|
||||||
// This does not affect the rename process, but the cache information in
|
// This does not affect the rename process, but the cache information in
|
||||||
// the "modified" state remains, making it impossible to read the file correctly.
|
// the "modified" state remains, making it impossible to read the file correctly.
|
||||||
//
|
//
|
||||||
ent = autoent.Open(from, &meta, stbuf.st_size, mtime, O_RDONLY, false, true, false);
|
FileTimes ts_times;
|
||||||
|
ts_times.SetAll(ctime, atime, mtime, false);
|
||||||
|
|
||||||
|
ent = autoent.Open(from, &meta, stbuf.st_size, ts_times, O_RDONLY, false, true, false);
|
||||||
}
|
}
|
||||||
if(ent){
|
if(ent){
|
||||||
if(0 != (result = ent->SetMCtime(mtime, ctime))){
|
if(0 != (result = ent->SetMtime(mtime)) || 0 != (result = ent->SetCtime(ctime)) || 0 != (result = ent->SetAtime(atime))){
|
||||||
S3FS_PRN_ERR("could not set mtime and ctime to file(%s): result=%d", from, result);
|
S3FS_PRN_ERR("could not set mtime/ctime/atime to file(%s): result=%d", from, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
ent->SetAtime(atime);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1592,6 +1583,7 @@ static int rename_object(const char* from, const char* to, bool update_ctime)
|
|||||||
|
|
||||||
// Add only stat structure to stat cache
|
// Add only stat structure to stat cache
|
||||||
std::string strTo = to;
|
std::string strTo = to;
|
||||||
|
|
||||||
stbuf = {};
|
stbuf = {};
|
||||||
if(convert_header_to_stat(strTo, meta, stbuf)){
|
if(convert_header_to_stat(strTo, meta, stbuf)){
|
||||||
objtype_t ObjType = derive_object_type(strTo, meta, objtype_t::FILE);
|
objtype_t ObjType = derive_object_type(strTo, meta, objtype_t::FILE);
|
||||||
@ -2691,16 +2683,12 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2])
|
|||||||
AutoFdEntity autoent;
|
AutoFdEntity autoent;
|
||||||
FdEntity* ent;
|
FdEntity* ent;
|
||||||
bool need_put_header = true;
|
bool need_put_header = true;
|
||||||
bool keep_mtime = false;
|
|
||||||
if(nullptr != (ent = autoent.OpenExistFdEntity(curpath.c_str()))){
|
if(nullptr != (ent = autoent.OpenExistFdEntity(curpath.c_str()))){
|
||||||
if(ent->MergeOrgMeta(updatemeta)){
|
if(ent->MergeOrgMeta(updatemeta)){
|
||||||
// meta is changed, but now uploading.
|
// meta is changed, but now uploading.
|
||||||
// then the meta is pending and accumulated to be put after the upload is complete.
|
// then the meta is pending and accumulated to be put after the upload is complete.
|
||||||
S3FS_PRN_INFO("meta pending until upload is complete");
|
S3FS_PRN_INFO("meta pending until upload is complete");
|
||||||
need_put_header = false;
|
need_put_header = false;
|
||||||
if(!ent->SetHoldingMtime(mtime)){
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get current entity's meta headers
|
// get current entity's meta headers
|
||||||
if(!ent->GetOrgMeta(meta)){
|
if(!ent->GetOrgMeta(meta)){
|
||||||
@ -2732,13 +2720,6 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2])
|
|||||||
|
|
||||||
}else{
|
}else{
|
||||||
S3FS_PRN_INFO("meta is not pending, but need to keep current mtime.");
|
S3FS_PRN_INFO("meta is not pending, but need to keep current mtime.");
|
||||||
|
|
||||||
// [NOTE]
|
|
||||||
// Depending on the order in which write/flush and utimens are called,
|
|
||||||
// the mtime updated here may be overwritten at the time of flush.
|
|
||||||
// To avoid that, set a special flag.
|
|
||||||
//
|
|
||||||
keep_mtime = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(need_put_header){
|
if(need_put_header){
|
||||||
@ -2761,12 +2742,6 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2])
|
|||||||
S3FS_PRN_ERR("failed convert headers to stat[path=%s]. So remove stat cache.", curpath.c_str());
|
S3FS_PRN_ERR("failed convert headers to stat[path=%s]. So remove stat cache.", curpath.c_str());
|
||||||
StatCache::getStatCacheData()->DelStat(curpath);
|
StatCache::getStatCacheData()->DelStat(curpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(keep_mtime){
|
|
||||||
if(!ent->SetHoldingMtime(mtime)){
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2860,15 +2835,9 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2])
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set mtime/ctime
|
// set mtime/ctime/atime
|
||||||
if(0 != (result = ent->SetMCtime(mtime, ctime))){
|
if(0 != (result = ent->SetMtime(mtime)) || 0 != (result = ent->SetCtime(ctime)) || 0 != (result = ent->SetAtime(atime))){
|
||||||
S3FS_PRN_ERR("could not set mtime and ctime to file(%s): result=%d", curpath.c_str(), result);
|
S3FS_PRN_ERR("could not set mtime/ctime/atime to file(%s): result=%d", curpath.c_str(), result);
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set atime
|
|
||||||
if(0 != (result = ent->SetAtime(atime))){
|
|
||||||
S3FS_PRN_ERR("could not set atime to file(%s): result=%d", curpath.c_str(), result);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2936,12 +2905,9 @@ static int s3fs_truncate(const char* _path, off_t size)
|
|||||||
ignore_modify = true;
|
ignore_modify = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nullptr == (ent = autoent.Open(path, &meta, size, S3FS_OMIT_TS, O_RDWR, false, true, ignore_modify))){
|
FileTimes ts_times; // Default: all time values are set UTIME_OMIT
|
||||||
S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno);
|
if(nullptr == (ent = autoent.Open(path, &meta, size, ts_times, O_RDWR, false, true, ignore_modify))){
|
||||||
return -EIO;
|
S3FS_PRN_ERR("could not open file(%s): errno=%d(ent is null(%p))", path, errno, ent); // [NOTE] read ent to avoid errors with cppcheck etc
|
||||||
}
|
|
||||||
if(!ent->UpdateCtime()){
|
|
||||||
S3FS_PRN_ERR("could not update ctime file(%s)", path);
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2974,7 +2940,8 @@ static int s3fs_truncate(const char* _path, off_t size)
|
|||||||
meta["x-amz-meta-uid"] = std::to_string(pcxt->uid);
|
meta["x-amz-meta-uid"] = std::to_string(pcxt->uid);
|
||||||
meta["x-amz-meta-gid"] = std::to_string(pcxt->gid);
|
meta["x-amz-meta-gid"] = std::to_string(pcxt->gid);
|
||||||
|
|
||||||
if(nullptr == (ent = autoent.Open(path, &meta, size, S3FS_OMIT_TS, O_RDWR, true, true, false))){
|
FileTimes ts_times; // Default: all time values are set UTIME_OMIT
|
||||||
|
if(nullptr == (ent = autoent.Open(path, &meta, size, ts_times, O_RDWR, true, true, false))){
|
||||||
S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno);
|
S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@ -3052,28 +3019,23 @@ static int s3fs_open(const char* _path, struct fuse_file_info* fi)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)){
|
|
||||||
st.st_mtime = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 != (result = get_object_attribute(path, nullptr, &meta, true, nullptr, true))){ // no truncate cache
|
if(0 != (result = get_object_attribute(path, nullptr, &meta, true, nullptr, true))){ // no truncate cache
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec st_mctime;
|
FileTimes ts_times; // Default: all time values are set UTIME_OMIT
|
||||||
set_stat_to_timespec(st, stat_time_type::MTIME, st_mctime);
|
ts_times.SetAll(st);
|
||||||
|
if(nullptr == (ent = autoent.Open(path, &meta, st.st_size, ts_times, fi->flags, false, true, false))){
|
||||||
if(nullptr == (ent = autoent.Open(path, &meta, st.st_size, st_mctime, fi->flags, false, true, false))){
|
|
||||||
// remove stat cache
|
// remove stat cache
|
||||||
StatCache::getStatCacheData()->DelStat(path);
|
StatCache::getStatCacheData()->DelStat(path);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_flush){
|
if (needs_flush){
|
||||||
struct timespec ts;
|
struct timespec ts_now;
|
||||||
s3fs_realtime(ts);
|
s3fs_realtime(ts_now);
|
||||||
|
if(0 != (result = ent->SetCtime(ts_now)) || 0 != (result = ent->SetMtime(ts_now))){
|
||||||
if(0 != (result = ent->SetMCtime(ts, ts))){
|
|
||||||
S3FS_PRN_ERR("could not set mtime and ctime to file(%s): result=%d", path, result);
|
S3FS_PRN_ERR("could not set mtime and ctime to file(%s): result=%d", path, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -3137,6 +3099,14 @@ static int s3fs_write(const char* _path, const char* buf, size_t size, off_t off
|
|||||||
S3FS_PRN_WARN("failed to write file(%s). result=%zd", path, res);
|
S3FS_PRN_WARN("failed to write file(%s). result=%zd", path, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int result;
|
||||||
|
struct timespec ts_now;
|
||||||
|
s3fs_realtime(ts_now);
|
||||||
|
if(0 != (result = ent->SetCtime(ts_now)) || 0 != (result = ent->SetMtime(ts_now))){
|
||||||
|
S3FS_PRN_ERR("could not set mtime and ctime to file(%s): result=%d", path, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if(max_dirty_data != -1 && ent->BytesModified() >= max_dirty_data){
|
if(max_dirty_data != -1 && ent->BytesModified() >= max_dirty_data){
|
||||||
int flushres;
|
int flushres;
|
||||||
if(0 != (flushres = ent->RowFlush(static_cast<int>(fi->fh), path, true))){
|
if(0 != (flushres = ent->RowFlush(static_cast<int>(fi->fh), path, true))){
|
||||||
@ -3208,15 +3178,6 @@ static int s3fs_flush(const char* _path, struct fuse_file_info* fi)
|
|||||||
if(nullptr != (ent = autoent.GetExistFdEntity(path, static_cast<int>(fi->fh)))){
|
if(nullptr != (ent = autoent.GetExistFdEntity(path, static_cast<int>(fi->fh)))){
|
||||||
bool is_new_file = ent->IsDirtyNewFile();
|
bool is_new_file = ent->IsDirtyNewFile();
|
||||||
|
|
||||||
if(!ent->UpdateMtime()){ // clear the flag not to update mtime.
|
|
||||||
S3FS_PRN_ERR("could not update mtime file(%s)", path);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
if(!ent->UpdateCtime()){
|
|
||||||
S3FS_PRN_ERR("could not update ctime file(%s)", path);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 == (result = ent->Flush(static_cast<int>(fi->fh), false))){
|
if(0 == (result = ent->Flush(static_cast<int>(fi->fh), false))){
|
||||||
// [NOTE]
|
// [NOTE]
|
||||||
// If there is any meta information that needs to be updated, update it now.
|
// If there is any meta information that needs to be updated, update it now.
|
||||||
@ -3269,16 +3230,6 @@ static int s3fs_fsync(const char* _path, int datasync, struct fuse_file_info* fi
|
|||||||
if(nullptr != (ent = autoent.GetExistFdEntity(path, static_cast<int>(fi->fh)))){
|
if(nullptr != (ent = autoent.GetExistFdEntity(path, static_cast<int>(fi->fh)))){
|
||||||
bool is_new_file = ent->IsDirtyNewFile();
|
bool is_new_file = ent->IsDirtyNewFile();
|
||||||
|
|
||||||
if(0 == datasync){
|
|
||||||
if(!ent->UpdateMtime()){
|
|
||||||
S3FS_PRN_ERR("could not update mtime file(%s)", path);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
if(!ent->UpdateCtime()){
|
|
||||||
S3FS_PRN_ERR("could not update ctime file(%s)", path);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = ent->Flush(static_cast<int>(fi->fh), false);
|
result = ent->Flush(static_cast<int>(fi->fh), false);
|
||||||
|
|
||||||
if(0 != datasync){
|
if(0 != datasync){
|
||||||
|
|||||||
@ -413,124 +413,6 @@ void print_launch_message(int argc, char** argv)
|
|||||||
S3FS_PRN_LAUNCH_INFO("%s", message.c_str());
|
S3FS_PRN_LAUNCH_INFO("%s", message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// result: -1 ts1 < ts2
|
|
||||||
// 0 ts1 == ts2
|
|
||||||
// 1 ts1 > ts2
|
|
||||||
//
|
|
||||||
constexpr 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(stat_time_type::ATIME == type){
|
|
||||||
#ifdef __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(stat_time_type::MTIME == type){
|
|
||||||
#ifdef __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(stat_time_type::CTIME == type){
|
|
||||||
#ifdef __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.", static_cast<int>(type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct timespec* set_stat_to_timespec(const struct stat& st, stat_time_type type, struct timespec& ts)
|
|
||||||
{
|
|
||||||
if(stat_time_type::ATIME == type){
|
|
||||||
#ifdef __APPLE__
|
|
||||||
ts.tv_sec = st.st_atime;
|
|
||||||
ts.tv_nsec = st.st_atimespec.tv_nsec;
|
|
||||||
#else
|
|
||||||
ts = st.st_atim;
|
|
||||||
#endif
|
|
||||||
}else if(stat_time_type::MTIME == type){
|
|
||||||
#ifdef __APPLE__
|
|
||||||
ts.tv_sec = st.st_mtime;
|
|
||||||
ts.tv_nsec = st.st_mtimespec.tv_nsec;
|
|
||||||
#else
|
|
||||||
ts = st.st_mtim;
|
|
||||||
#endif
|
|
||||||
}else if(stat_time_type::CTIME == type){
|
|
||||||
#ifdef __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.", static_cast<int>(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(nullptr);
|
|
||||||
ts.tv_nsec = 0;
|
|
||||||
}
|
|
||||||
return &ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string s3fs_str_realtime()
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
return str(*s3fs_realtime(ts));
|
|
||||||
}
|
|
||||||
|
|
||||||
int s3fs_fclose(FILE* fp)
|
int s3fs_fclose(FILE* fp)
|
||||||
{
|
{
|
||||||
if(fp == nullptr){
|
if(fp == nullptr){
|
||||||
|
|||||||
@ -59,55 +59,40 @@ bool compare_sysname(const char* target);
|
|||||||
|
|
||||||
void print_launch_message(int argc, char** argv);
|
void print_launch_message(int argc, char** argv);
|
||||||
|
|
||||||
//
|
|
||||||
// Utility for nanosecond time(timespec)
|
|
||||||
//
|
|
||||||
enum class stat_time_type : uint8_t {
|
|
||||||
ATIME,
|
|
||||||
MTIME,
|
|
||||||
CTIME
|
|
||||||
};
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Utility for nanosecond time(timespec)
|
// Utility for nanosecond time(timespec)
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
static constexpr struct timespec S3FS_OMIT_TS = {0, UTIME_OMIT};
|
|
||||||
|
|
||||||
constexpr 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();
|
|
||||||
|
|
||||||
// Wrap fclose since it is illegal to take the address of a stdlib function
|
// Wrap fclose since it is illegal to take the address of a stdlib function
|
||||||
int s3fs_fclose(FILE* fp);
|
int s3fs_fclose(FILE* fp);
|
||||||
|
|
||||||
class scope_guard {
|
class scope_guard
|
||||||
public:
|
{
|
||||||
template<class Callable>
|
public:
|
||||||
explicit scope_guard(Callable&& undo_func)
|
template<class Callable>
|
||||||
: func(std::forward<Callable>(undo_func))
|
|
||||||
{}
|
|
||||||
|
|
||||||
~scope_guard() {
|
explicit scope_guard(Callable&& undo_func)
|
||||||
if(func != nullptr) {
|
: func(std::forward<Callable>(undo_func))
|
||||||
func();
|
{}
|
||||||
|
|
||||||
|
~scope_guard()
|
||||||
|
{
|
||||||
|
if(func != nullptr) {
|
||||||
|
func();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void dismiss() {
|
void dismiss()
|
||||||
func = nullptr;
|
{
|
||||||
}
|
func = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
scope_guard(const scope_guard&) = delete;
|
scope_guard(const scope_guard&) = delete;
|
||||||
scope_guard(scope_guard&& other) = delete;
|
scope_guard(scope_guard&& other) = delete;
|
||||||
scope_guard& operator=(const scope_guard&) = delete;
|
scope_guard& operator=(const scope_guard&) = delete;
|
||||||
scope_guard& operator=(scope_guard&&) = delete;
|
scope_guard& operator=(scope_guard&&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::function<void()> func;
|
std::function<void()> func;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // S3FS_S3FS_UTIL_H_
|
#endif // S3FS_S3FS_UTIL_H_
|
||||||
|
|||||||
@ -27,24 +27,28 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "s3fs_logger.h"
|
#include "s3fs_logger.h"
|
||||||
#include "string_util.h"
|
#include "string_util.h"
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
// Global variables
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Functions
|
// Functions
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
std::string str(const struct timespec& value)
|
std::string str(const struct timespec& value)
|
||||||
{
|
{
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << value.tv_sec;
|
|
||||||
if(value.tv_nsec != 0){
|
if(UTIME_OMIT == value.tv_nsec){
|
||||||
s << "." << std::setfill('0') << std::setw(9) << value.tv_nsec;
|
s << "UTIME_OMIT";
|
||||||
|
}else if(UTIME_NOW == value.tv_nsec){
|
||||||
|
s << "UTIME_NOW";
|
||||||
|
}else{
|
||||||
|
s << value.tv_sec;
|
||||||
|
if(value.tv_nsec != 0){
|
||||||
|
s << "." << std::setfill('0') << std::setw(9) << value.tv_nsec;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user