From: Hamatoma Date: Sat, 21 Feb 2015 15:17:27 +0000 (+0100) Subject: win corrections, ReDirectory::deleteTree() X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=450e9879a00ca41582b5f50d7b02bf5251104427;p=crepublib win corrections, ReDirectory::deleteTree() --- diff --git a/base/ReByteBuffer.cpp b/base/ReByteBuffer.cpp index 65a01f0..f12c8d2 100644 --- a/base/ReByteBuffer.cpp +++ b/base/ReByteBuffer.cpp @@ -461,10 +461,12 @@ int ReByteBuffer::count(const char* toCount, size_t lengthToCount){ */ bool ReByteBuffer::endsWith(const Byte* tail, size_t tailLength, bool ignoreCase) const { - bool rc; - if (tailLength == (size_t)-1) - tailLength = strlen(tail); - rc = indexOf(tail, tailLength, m_length - tailLength, m_length, ignoreCase) >= 0; + bool rc = tail != NULL; + if (rc){ + if (tailLength == (size_t)-1) + tailLength = strlen(tail); + rc = indexOf(tail, tailLength, m_length - tailLength, m_length, ignoreCase) >= 0; + } return rc; } @@ -785,10 +787,12 @@ bool ReByteBuffer::splice(size_t ix, size_t replacedLength, * false: otherwise */ bool ReByteBuffer::startsWith(const Byte* head, size_t headLength, const bool ignoreCase) const{ - bool rc; - if (headLength == (size_t) -1) - headLength = strlen(head); - rc = indexOf(head, headLength, 0, headLength, ignoreCase) == 0; + bool rc = head != NULL; + if (rc){ + if (headLength == (size_t) -1) + headLength = strlen(head); + rc = indexOf(head, headLength, 0, headLength, ignoreCase) == 0; + } return rc; } diff --git a/base/ReDirectory.cpp b/base/ReDirectory.cpp index 784f037..1982c94 100644 --- a/base/ReDirectory.cpp +++ b/base/ReDirectory.cpp @@ -67,55 +67,55 @@ ReDirectory::~ReDirectory(){ #elif defined __WIN32__ #endif } -/** @brief Sets the directory. +/** @brief Returns the name of the current file found by the last findFirst() + * or findNext(). + * + * @return NULL: No current file exists. Otherwise: The name of the current file. * - * @param path The name of the directory. */ -void ReDirectory::setDir(const char* path){ - m_path.set(path, -1); +const char* ReDirectory::currentFile(){ #if defined __linux__ - if (m_dir != NULL){ - closedir(m_dir); - m_dir = NULL; - } - m_entry = NULL; - m_dir = opendir(path); - m_valid = m_dir != NULL; - if (m_valid){ - if (m_path.at(m_path.length() - 1) != OS_SEPARATOR_CHAR) - m_path.append(OS_SEPARATOR, 1); - } + const char* rc = m_entry == NULL ? NULL : m_entry->d_name; #elif defined __WIN32__ - struct stat info; - ReByteBuffer thePath(m_path); - if (m_path.endsWith(OS_SEPARATOR)) - thePath.setLength(thePath.length() - 1); - m_valid = stat(thePath.str(), &info) == 0 && S_ISDIR(info.st_mode); + const char* rc = m_data.cFileName; #endif -} -/** @brief Returns the name of the directory. - * - * @return The name of the directory. - */ -const char* ReDirectory::getDir(void) const { - return m_path.buffer(); + return rc; } -/** @brief Tests whether the directory state is valid. +/** + * Deletes a directory tree. * - * @return true: The instance is OK. false: Some error has occurred. + * @param base the name of the directory + * @param deleteBaseToo true: the directory itself will be deleted + * false: only the files and subdirs in the dir will be deleted */ -bool ReDirectory::isValid(){ - return m_valid; +void ReDirectory::deleteTree(const char* base, bool deleteBaseToo){ + ReDirectory dir(base); + if (dir.findFirst("*", false)){ + ReByteBuffer full; + do { + struct stat info; + const char* node = dir.currentFile(); + if (! (node[0] == '.' && (node[1] == '\0' || node[1] == '.' && node[2] == '\0')) + && stat(dir.fullpath(full).str(), &info) == 0){ + if (S_ISDIR(info.st_mode)) + deleteTree(full.str(), true); + else + _unlink(full.str()); + } + } while(dir.findNext()); + } + if (deleteBaseToo){ + _rmdir(base); + } } -/** @brief Sets the flags of the regular expression handling. + +/** @brief Returns the name of the directory. * - * @param flags Usefull flags are: REG_ICASE: ignore case. + * @return The name of the directory. */ -void ReDirectory::setRegExprFlags(int flags){ -#if defined __linux__ - m_regExprFlags = flags; -#endif +const char* ReDirectory::getDir(void) const { + return m_path.buffer(); } /** @brief Find the first file with a given filename pattern. @@ -160,7 +160,8 @@ bool ReDirectory::findFirst(const char* pattern, bool isRegExpr){ } /** @brief Find the next file with the pattern defined with the last findFirst() call. * - * @return true: A file has been found. false: The directory contains no more file with the given pattern. + * @return true: a file has been found
+ * false: the directory contains no more file with the given pattern */ bool ReDirectory::findNext(){ bool rc = false; @@ -235,20 +236,7 @@ bool ReDirectory::findYoungest(ReByteBuffer& filename){ #endif return rc; } -/** @brief Returns the name of the current file found by the last findFirst() - * or findNext(). - * - * @return NULL: No current file exists. Otherwise: The name of the current file. - * - */ -const char* ReDirectory::currentFile(){ -#if defined __linux__ - const char* rc = m_entry == NULL ? NULL : m_entry->d_name; -#elif defined __WIN32__ - const char* rc = m_data.cFileName; -#endif - return rc; -} + /** @brief Returns the full path of the current file or a given node. * * The current file is the file found by the last call of findFirst() or findNext(). @@ -279,10 +267,46 @@ ReByteBuffer& ReDirectory::fullpath(ReByteBuffer& path, const char* name){ return path; } -/** @brief Find the first file matching a given filename pattern. +/** @brief Tests whether the directory state is valid. + * + * @return true: The instance is OK. false: Some error has occurred. + */ +bool ReDirectory::isValid(){ + return m_valid; +} + +/** @brief Sets the directory. + * + * @param path The name of the directory. + */ +void ReDirectory::setDir(const char* path){ + m_path.set(path, -1); +#if defined __linux__ + if (m_dir != NULL){ + closedir(m_dir); + m_dir = NULL; + } + m_entry = NULL; + m_dir = opendir(path); + m_valid = m_dir != NULL; +#elif defined __WIN32__ + struct stat info; + ReByteBuffer thePath(m_path); + if (m_path.endsWith(OS_SEPARATOR)) + thePath.setLength(thePath.length() - 1); + m_valid = stat(thePath.str(), &info) == 0 && S_ISDIR(info.st_mode); +#endif + if (m_path.at(m_path.length() - 1) != OS_SEPARATOR_CHAR) + m_path.append(OS_SEPARATOR, 1); +} + +/** @brief Sets the flags of the regular expression handling. * - * @param dir The directory handle. - * @param pattern The pattern for the searched files. May contain wildcards. - * @param useRegExpr True: pattern is a regular expression. + * @param flags Usefull flags are: REG_ICASE: ignore case. */ +void ReDirectory::setRegExprFlags(int flags){ +#if defined __linux__ + m_regExprFlags = flags; +#endif +} diff --git a/base/ReDirectory.hpp b/base/ReDirectory.hpp index f51df7c..0739fac 100644 --- a/base/ReDirectory.hpp +++ b/base/ReDirectory.hpp @@ -17,15 +17,17 @@ public: ReDirectory(const char* path); ~ReDirectory(); public: - void setDir(const char* path); - const char* getDir(void) const; - bool isValid(); - void setRegExprFlags(int flags); + const char* currentFile(); bool findFirst(const char* pattern, bool isRegExpr); bool findNext(); bool findYoungest(ReByteBuffer& filename); - const char* currentFile(); ReByteBuffer& fullpath(ReByteBuffer& path, const char* name = NULL); + const char* getDir(void) const; + bool isValid(); + void setDir(const char* path); + void setRegExprFlags(int flags); +public: + static void deleteTree(const char* base, bool deleteBaseToo = false); private: //@ true: The directory is ok. false: The directory is undefined. bool m_valid; diff --git a/base/ReStringList.cpp b/base/ReStringList.cpp index 96a45cd..a8b7c6d 100644 --- a/base/ReStringList.cpp +++ b/base/ReStringList.cpp @@ -298,7 +298,7 @@ ReSeqArray::Index ReStringList::nextStartingWith(Index start, void ReStringList::split(const char* list, char separator, bool append){ if (! append) clear(); - const char* end = strchr(list, separator); + const char* end = list == NULL ? NULL : strchr(list, separator); const char* end2; ReByteBuffer item; while(end != NULL){ @@ -316,7 +316,7 @@ void ReStringList::split(const char* list, char separator, bool append){ list++; end = strchr(list, separator); } - if (list[0] != '\0') + if (list != NULL && list[0] != '\0') add(-1, list, strlen(list) + 1); } /** @brief Joins all string members into a string. diff --git a/base/ReTestUnit.cpp b/base/ReTestUnit.cpp index 7323c6c..9d89d5c 100644 --- a/base/ReTestUnit.cpp +++ b/base/ReTestUnit.cpp @@ -122,6 +122,8 @@ void ReTestUnit::assertEqual(unsigned int expected, unsigned int current, int li * @param lineNo the line number of the test (for the error message) */ void ReTestUnit::assertEqual(const char* expected, const char* current, int lineNo){ + if (expected == NULL) + expected = ""; if (current == NULL || strcmp(expected, current) != 0){ logF(true, i18n("%s-%d: expected / current: length: %d / %d\n%.512s\n%.512s"), m_sourceFile.str(), lineNo, strlen(expected), current == NULL ? 0 : strlen(current), diff --git a/cunit/cuReDirTools.cpp b/cunit/cuReDirTools.cpp index d2d8994..5c29591 100644 --- a/cunit/cuReDirTools.cpp +++ b/cunit/cuReDirTools.cpp @@ -16,6 +16,7 @@ class TestReDirTools : public ReTestUnit { public: TestReDirTools() : ReTestUnit("ReTraverser", __FILE__){ m_base = testDir(); + ReDirectory::deleteTree(m_base.str()); m_base.append("traverser").append(OS_SEPARATOR, -1); _mkdir(m_base.str(), ALLPERMS); run(); @@ -252,9 +253,14 @@ private: ReStringList cols; for (size_t ix = 0; ix < current.count(); ix++){ line.setLength(0).append(current.strOf(ix), -1); +#if defined __WIN32__ + line.replaceAll(OS_SEPARATOR, 1, "/", 1); +#endif cols.split(expected.strOf(ix), '*'); - checkT(line.startsWith(cols.strOf(0))); - checkT(line.endsWith(cols.strOf(1))); + if (! line.startsWith(cols.strOf(0))) + checkEqu(cols.strOf(0), line.str()); + if (! line.endsWith(cols.strOf(1))) + checkEqu(cols.strOf(1), line.str()); } } void testTouch(){ @@ -271,7 +277,8 @@ private: "2015.03.28 10:21:31 *traverser/1.txt\n" "2015.03.28 10:21:31 *traverser/dir1/dir1_2/dir1_2_1/x1.txt\n" "2015.03.28 10:21:31 *traverser/dir1/dir1_2/dir1_2_1/x2.txt\n" - "=== 3 file(s) 0.000059 MByte 0 dirs(s) * sec"); + "=== filtered: 3 file(s) 0.000059 MByte 0 dirs(s) * sec\n" + "=== total: 4 file(s) 0.000067 MByte 6 dirs(s) * sec"); const char* argv2[] = { "dt", "list", "-P;*;-cache", "-tr", "-p;*.txt", optOutput.str(), m_base.str(), NULL }; diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index 232b230..32b34b6 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -699,11 +699,11 @@ void ReTool::run(int argc, const char** argv){ */ void ReTool::processFileArguments(){ int max = m_programArgs.getArgCount() - m_reservedLast; - struct stat info; // Test whether the arguments are files or directories: + ReByteBuffer arg; for (int ii = m_reservedFirst; ii < max; ii++){ - const char* arg = m_programArgs.getArg(ii); - if (stat(arg, &info) != 0) + arg = m_programArgs.getArg(ii); + if (! exists(arg) != 0) m_programArgs.help( ReByteBuffer(i18n("not a file or a directory: ")).append(arg).str(), false, stderr); @@ -711,7 +711,7 @@ void ReTool::processFileArguments(){ // process the files: for (int ii = m_reservedFirst; ii < max; ii++){ const char* arg = m_programArgs.getArg(ii); - if (S_ISDIR(info.st_mode)) + if (S_ISDIR(m_statInfo.st_mode)) processTree(arg); else processSingleFile(arg); @@ -794,14 +794,21 @@ void ReTool::processFile(ReDirStatus_t* entry){ } /** * Issues a summary message if verbose level allows this. + * + * @param prefix NULL or a line prefix */ -void ReTool::printSummary(){ +void ReTool::printSummary(const char* prefix){ if (m_verboseLevel >= V_SUMMARY){ int duration = int(time(NULL) - m_start); ReByteBuffer line; + ReByteBuffer line2; statisticAsString(line); - line.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec")); - fprintf(m_output, "=== %s\n", line.str()); + double rate = duration == 0 ? 0.0 : (m_files + m_directories) / duration; + line.append(rate, " %.1f").append(i18n("/sec"), -1); + m_traverser.statisticAsString(line2); + line2.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec")); + fprintf(m_output, "%s=== filtered: %s\n", prefix == NULL ? "" : prefix, line.str()); + fprintf(m_output, "%s=== total: %s\n", prefix == NULL ? "" : prefix, line2.str()); } } @@ -1296,15 +1303,14 @@ void ReDirTouch::processDir(ReDirStatus_t* entry){ } static bool isAbsoluteTime(ReFileTime_t& time){ +#if defined __linux__ static struct tm year1980 = { 0, 0, 0, 1, 1 - 1, 1980-1900 }; static time_t time1980 = mktime(&year1980); -#if defined __linux__ return time.tv_sec >= time1980; #elif defined __WIN32__ - static ReFileTime_t time2 = { 0, 0 }; - if (time2.dwHighDateTime == 0 && time2.dwLowDateTime == 0) - ReDirStatus_t::timeToFiletime(time1980, time2); - return time2 > time; + static ReFileTime_t filetime1980 = { 2148603904, 27846551 }; + bool rc = time > filetime1980; + return rc; #endif } static void addRelativeTime(ReFileTime_t& absTime, const ReFileTime_t& relTime){ @@ -1461,11 +1467,7 @@ void ReDirTools::usage(const char* msg, const char* msg2){ */ void ReDirSync::makeDirWithParents(ReByteBuffer& path, int minWidth, ReTraverser& traverser){ - struct stat info; - bool endsWithSlash = path.str()[path.length() - 1] == OS_SEPARATOR_CHAR; - if (endsWithSlash) - path.setLength(path.length() - 1); - if (stat(path.str(), &info) != 0){ + if (! exists(path)){ ReFileProperties_t* props = NULL; #if defined __linux__ ReDirStatus_t* entry = traverser.topOfStack(); @@ -1473,8 +1475,6 @@ void ReDirSync::makeDirWithParents(ReByteBuffer& path, int minWidth, #endif makeDirectory(path.str(), minWidth, props, ReLogger::globalLogger()); } - if (endsWithSlash) - path.append(OS_SEPARATOR, 1); } /** * Constructor. @@ -1711,14 +1711,13 @@ bool ReDirSync::makeDirectory(const char* directory, int minLength, void ReDirSync::doIt(){ ReDirEntryFilter_t filter; const char* sep = OS_SEPARATOR; - struct stat info; ReByteBuffer buffer; ReByteBuffer target(m_programArgs.getArg(m_programArgs.getArgCount() - 1)); - if (target.endsWith(sep, 1)) - target.setLength(target.length() - 1); - if (stat(target.str(), &info) != 0) + if (target.endsWith(OS_SEPARATOR)) + target.setLength(target.length() - 1); + if (! exists(target)) help(i18n("target does not exist: $1"), target.str()); - else if (! S_ISDIR(info.st_mode)) + else if (! S_ISDIR(m_statInfo.st_mode)) help(i18n("target is not a directory: $1"), target.str()); size_t lengthTargetBase = target.length(); bool addOnly = m_programArgs.getBool("add"); @@ -1739,9 +1738,9 @@ void ReDirSync::doIt(){ bool endsWithSlash = source.endsWith(sep, 1); if (endsWithSlash) source.setLength(source.length() - 1); - if (stat(source.str(), &info) != 0) + if (! exists(source)) help(i18n("source does not exist: $1"), source.str()); - else if (! S_ISDIR(info.st_mode)) + else if (! S_ISDIR(m_statInfo.st_mode)) help(i18n("source is not a directory: $1"), source.str()); if (! endsWithSlash){ // the basename of the source will be appended to the target: @@ -1763,30 +1762,30 @@ void ReDirSync::doIt(){ // append the new relative path from source to target: target.setLength(ixTargetRelative); target.append(entry->m_path.str() + ixSourceRelative, -1); - if (stat(target.str(), &info) != 0) + if (! exists(target)) makeDirWithParents(target, ixTargetRelative, traverser); targetFile.set(target).append(entry->node(), -1); const char* targetRelativePath = targetFile.str() + ixTargetRelative + 1; - bool exists = stat(targetFile.str(), &info) == 0; - if (! exists && mustExist){ + bool targetExists = exists(targetFile); + if (! targetExists && mustExist){ if (m_verboseLevel == V_CHATTER) fprintf(m_output, "-ignored: %s does not exist\n", targetRelativePath); continue; } - if (exists){ + if (targetExists){ if (addOnly){ if (m_verboseLevel >= V_CHATTER) fprintf(m_output, "~ignored: %s exists\n", targetRelativePath); continue; } - if (ignoreDate && entry->fileSize() == info.st_size){ + if (ignoreDate && entry->fileSize() == m_statInfo.st_size){ if (m_verboseLevel >= V_CHATTER) fprintf(m_output, "_ignored: %s same size\n", targetRelativePath); continue; } // target younger than source? - int diff = int(info.st_mtime - entry->filetimeToTime(entry->modified())); - if (! ignoreDate && info.st_mtime - entry->filetimeToTime(entry->modified()) + int diff = int(m_statInfo.st_mtime - entry->filetimeToTime(entry->modified())); + if (! ignoreDate && m_statInfo.st_mtime - entry->filetimeToTime(entry->modified()) <= maxFileTimeDiff) { if (m_verboseLevel >= V_CHATTER) fprintf(m_output, "=ignored: %s same time\n", targetRelativePath); @@ -1796,7 +1795,7 @@ void ReDirSync::doIt(){ files++; sumSizes += entry->fileSize(); if (m_verboseLevel >= V_NORMAL) - fprintf(m_output, "%c%s%s\n", exists ? '!' : '+', targetRelativePath, + fprintf(m_output, "%c%s%s\n", targetExists ? '!' : '+', targetRelativePath, dry ? " would be copied" : ""); if (! dry) copyFile(entry, targetFile.str()); @@ -1809,7 +1808,7 @@ void ReDirSync::doIt(){ int duration = int(time(NULL) - m_start); fprintf(m_output, i18n( "=== copied: %02d:%02d sec %7d file(s) %12.6f MByte (%.3f MB/sec).\n" - "=== tree : %5d dir(s) %7d file(s) %12.6f MByte\n"), + "=== tree: %5d dir(s) %7d file(s) %12.6f MByte\n"), duration / 60, duration % 60, files, sumSizes / 1E6, sumSizes / 1E6 / (duration == 0 ? 1 : duration), treeDirs, treeFiles, treeSumSizes / 1E6); diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index c539d58..2fcf836 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -89,12 +89,32 @@ protected: * Normally it calls processFileArguments() after some initializations. */ virtual void doIt() = 0; - void printSummary(); + void printSummary(const char* prefix = NULL); virtual void processDir(ReDirStatus_t* status); virtual void processFile(ReDirStatus_t* status); void processFileArguments(); virtual void processSingleFile(const char* filename); virtual void processTree(const char* filename); + /** Tests whether a file or directory exists: + @param name can be changed and recovered! + @return true: a file with the given name exists + */ + inline bool exists(ReByteBuffer& name){ +#if defined __linux__ + // linux ignores a trailing slash: + return stat(name.str(), &m_statInfo) == 0; +#elif defined __WIN32__ + int ix = name.length() - 1; + if (ix >= 0 && name.str()[ix] != OS_SEPARATOR_CHAR) + ix = -1; + else + name.setLength(ix); + bool rc = stat(name.str(), &m_statInfo) == 0; + if (ix >= 0) + name.append(OS_SEPARATOR_CHAR); + return rc; +#endif + } protected: int m_minArguments; int m_reservedFirst; @@ -103,6 +123,7 @@ protected: ReTraverser m_traverser; ReDirEntryFilter_t m_filter; int64_t m_start; + struct stat m_statInfo; }; class ReDirBatch : public ReTool { diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index 30004cf..20e8d14 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -312,7 +312,7 @@ time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime){ #ifdef __linux__ return filetime->tv_sec; #elif defined __WIN32__ - // takes the last modified date + // 64-bit arithmetic: LARGE_INTEGER date, adjust; date.HighPart = filetime->dwHighDateTime; date.LowPart = filetime->dwLowDateTime; @@ -321,7 +321,8 @@ time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime){ // removes the diff between 1970 and 1601 date.QuadPart -= adjust.QuadPart; // converts back from 100-nanoseconds to seconds - return (time_t) (date.QuadPart / 10000000); + time_t rc = (time_t) (date.QuadPart / 10000000); + return rc; #endif } /**