From fad8f5151bc492f43769bc93c9997cb32a2a051a Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Fri, 8 Jan 2016 11:23:10 +0100 Subject: [PATCH] Centralize stat calls to ensure consistency of time fields on windows --- src/index/beaglequeue.cpp | 2 +- src/index/fsfetcher.cpp | 4 ++-- src/index/fsindexer.cpp | 5 ++--- src/internfile/internfile.cpp | 6 +++--- src/internfile/mh_text.cpp | 3 +-- src/qtgui/uiprefs_w.cpp | 4 ++++ src/utils/fstreewalk.cpp | 13 ++++++------- src/utils/pathut.cpp | 22 ++++++++++++++++++++++ src/utils/pathut.h | 11 +++++++++++ 9 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/index/beaglequeue.cpp b/src/index/beaglequeue.cpp index 20511e15..f6217f70 100644 --- a/src/index/beaglequeue.cpp +++ b/src/index/beaglequeue.cpp @@ -342,7 +342,7 @@ bool BeagleQueueIndexer::indexFiles(list& files) it++; continue; } struct stat st; - if (lstat(it->c_str(), &st) != 0) { + if (path_fileprops(*it, &st) != 0) { LOGERR(("BeagleQueueIndexer::indexfiles: cant stat [%s]\n", it->c_str())); it++; continue; diff --git a/src/index/fsfetcher.cpp b/src/index/fsfetcher.cpp index 5441f990..8210760e 100644 --- a/src/index/fsfetcher.cpp +++ b/src/index/fsfetcher.cpp @@ -21,11 +21,11 @@ #include "debuglog.h" #include "cstr.h" - #include "fetcher.h" #include "fsfetcher.h" #include "fsindexer.h" #include "debuglog.h" +#include "pathut.h" using std::string; @@ -43,7 +43,7 @@ static bool urltopath(RclConfig* cnf, bool follow = false; cnf->getConfParam("followLinks", &follow); - if ((follow ? stat(fn.c_str(), &st) : lstat(fn.c_str(), &st))< 0) { + if (path_fileprops(fn, &st, follow) < 0) { LOGERR(("FSDocFetcher::fetch: stat errno %d for [%s]\n", errno, fn.c_str())); return false; diff --git a/src/index/fsindexer.cpp b/src/index/fsindexer.cpp index 046335ab..55fc338f 100644 --- a/src/index/fsindexer.cpp +++ b/src/index/fsindexer.cpp @@ -362,10 +362,9 @@ bool FsIndexer::indexFiles(list& files, int flags) } struct stat stb; - int ststat = follow ? stat(it->c_str(), &stb) : - lstat(it->c_str(), &stb); + int ststat = path_fileprops(*it, &stb, follow); if (ststat != 0) { - LOGERR(("FsIndexer::indexFiles: lstat(%s): %s", it->c_str(), + LOGERR(("FsIndexer::indexFiles: (l)stat %s: %s", it->c_str(), strerror(errno))); it++; continue; diff --git a/src/internfile/internfile.cpp b/src/internfile/internfile.cpp index 6a50c04a..107d697d 100644 --- a/src/internfile/internfile.cpp +++ b/src/internfile/internfile.cpp @@ -195,7 +195,7 @@ void FileInterner::init(const string &f, const struct stat *stp, RclConfig *cnf, m_fn = m_tfile; // Stat the uncompressed file, mainly to get the size struct stat ucstat; - if (stat(m_fn.c_str(), &ucstat) != 0) { + if (path_fileprops(m_fn, &ucstat) != 0) { LOGERR(("FileInterner: can't stat the uncompressed file" "[%s] errno %d\n", m_fn.c_str(), errno)); return; @@ -1042,7 +1042,7 @@ bool FileInterner::isCompressed(const string& fn, RclConfig *cnf) { LOGDEB(("FileInterner::isCompressed: [%s]\n", fn.c_str())); struct stat st; - if (stat(fn.c_str(), &st) < 0) { + if (path_fileprops(fn, &st) < 0) { LOGERR(("FileInterner::isCompressed: can't stat [%s]\n", fn.c_str())); return false; } @@ -1066,7 +1066,7 @@ bool FileInterner::maybeUncompressToTemp(TempFile& temp, const string& fn, { LOGDEB(("FileInterner::maybeUncompressToTemp: [%s]\n", fn.c_str())); struct stat st; - if (stat(fn.c_str(), &st) < 0) { + if (path_fileprops(fn.c_str(), &st) < 0) { LOGERR(("FileInterner::maybeUncompressToTemp: can't stat [%s]\n", fn.c_str())); return false; diff --git a/src/internfile/mh_text.cpp b/src/internfile/mh_text.cpp index 3061ab5f..80da2733 100644 --- a/src/internfile/mh_text.cpp +++ b/src/internfile/mh_text.cpp @@ -20,7 +20,6 @@ #include #include "safefcntl.h" #include -#include "safesysstat.h" #include "safeunistd.h" #include @@ -56,7 +55,7 @@ bool MimeHandlerText::set_document_file(const string& mt, const string &fn) // file size for oversize check long long fsize = path_filesize(m_fn); if (fsize < 0) { - LOGERR(("MimeHandlerText::set_document_file: stat(%s) errno %d\n", + LOGERR(("MimeHandlerText::set_document_file: stat %s errno %d\n", m_fn.c_str(), errno)); return false; } diff --git a/src/qtgui/uiprefs_w.cpp b/src/qtgui/uiprefs_w.cpp index 0c529250..c6cb4c70 100644 --- a/src/qtgui/uiprefs_w.cpp +++ b/src/qtgui/uiprefs_w.cpp @@ -553,6 +553,9 @@ void UIPrefsDialog::delExtraDbPB_clicked() static bool samedir(const string& dir1, const string& dir2) { +#ifdef _WIN32 + return !dir1.compare(dir2); +#else struct stat st1, st2; if (stat(dir1.c_str(), &st1)) return false; @@ -562,6 +565,7 @@ static bool samedir(const string& dir1, const string& dir2) return true; } return false; +#endif } void UIPrefsDialog::on_showTrayIconCB_clicked() diff --git a/src/utils/fstreewalk.cpp b/src/utils/fstreewalk.cpp index 1b184fa6..5ffa7ba5 100644 --- a/src/utils/fstreewalk.cpp +++ b/src/utils/fstreewalk.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include "safesysstat.h" @@ -226,7 +225,7 @@ FsTreeWalker::Status FsTreeWalker::walk(const string& _top, data->basedepth = slashcount(top); // Only used for breadthxx struct stat st; // We always follow symlinks at this point. Makes more sense. - if (stat(top.c_str(), &st) == -1) { + if (path_fileprops(top, &st) == -1) { // Note that we do not return an error if the stat call // fails. A temp file may have gone away. data->logsyserr("stat", top); @@ -288,7 +287,7 @@ FsTreeWalker::Status FsTreeWalker::walk(const string& _top, // If changing parent directory, advise our user. if (!nfather.empty()) { - if (stat(nfather.c_str(), &st) == -1) { + if (path_fileprops(nfather, &st) == -1) { data->logsyserr("stat", nfather); return errno == ENOENT ? FtwOk : FtwError; } @@ -298,7 +297,7 @@ FsTreeWalker::Status FsTreeWalker::walk(const string& _top, } } - if (stat(dir.c_str(), &st) == -1) { + if (path_fileprops(dir, &st) == -1) { data->logsyserr("stat", dir); return errno == ENOENT ? FtwOk : FtwError; } @@ -397,7 +396,8 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top, fn = path_cat(top, ent->d_name); #ifdef _WIN32 - // readdir gets the useful attrs, no inode indirection on windows + // readdir gets the useful attrs, no inode indirection on windows, + // spare the path_fileprops() call, but make sure we mimick it. memset(&st, 0, sizeof(st)); st.st_mtime = ent->d_mtime; st.st_size = ent->d_size; @@ -407,8 +407,7 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top, // anyway. st.st_ctime = st.st_mtime; #else - int statret = (data->options & FtwFollow) ? stat(fn.c_str(), &st) : - lstat(fn.c_str(), &st); + int statret = path_fileprops(fn.c_str(), &st, data->options&FtwFollow); if (statret == -1) { data->logsyserr("stat", fn); continue; diff --git a/src/utils/pathut.cpp b/src/utils/pathut.cpp index 1697e031..468efd79 100644 --- a/src/utils/pathut.cpp +++ b/src/utils/pathut.cpp @@ -710,6 +710,28 @@ long long path_filesize(const string& path) return (long long)st.st_size; } +int path_fileprops(const std::string path, struct stat *stp, bool follow) +{ + if (!stp) + return -1; + memset(stp, 0, sizeof(struct stat)); + struct stat mst; + int ret = follow ? stat(path.c_str(), &mst) : lstat(path.c_str(), &mst); + if (ret != 0) + return ret; + stp->st_size = mst.st_size; + stp->st_mode = mst.st_mode; + stp->st_mtime = mst.st_mtime; +#ifdef _WIN32 + stp->st_ctime = mst.st_mtime; +#else + stp->st_ino = mst.st_ino; + stp->st_dev = mst.st_dev; + stp->st_ctime = mst.st_ctime; +#endif + return 0; +} + bool path_exists(const string& path) { return access(path.c_str(), 0) == 0; diff --git a/src/utils/pathut.h b/src/utils/pathut.h index a8c03d1f..10991edf 100644 --- a/src/utils/pathut.h +++ b/src/utils/pathut.h @@ -79,6 +79,17 @@ extern bool path_isdir(const std::string& path); /// Retrieve file size extern long long path_filesize(const std::string& path); +/// Retrieve essential file attributes. This is used rather than a +/// bare stat() to ensure consistent use of the time fields (on +/// windows, we set ctime=mtime as ctime is actually the creation +/// time, for which we have no use). +/// Only st_mtime, st_ctime, st_size, st_mode (file type bits) are set on +/// all systems. st_dev and st_ino are set for special posix usage. +/// The rest is zeroed. +struct stat; +extern int path_fileprops(const std::string path, struct stat *stp, + bool follow = true); + /// Check that path is traversable and last element exists /// Returns true if last elt could be checked to exist. False may mean that /// the file/dir does not exist or that an error occurred.