From: hama Date: Fri, 20 Feb 2015 22:37:44 +0000 (+0100) Subject: Refactoring: ReFileTime_t, touch X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=5979d2b6e8b035e8296ec20212e69ba62ab020c4;p=crepublib Refactoring: ReFileTime_t, touch --- diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp index 1ef93f9..701a742 100644 --- a/base/ReProgramArgs.cpp +++ b/base/ReProgramArgs.cpp @@ -27,8 +27,7 @@ ReOptionException::ReOptionException(ReProgramArgs* caller, const char* message, { ReVarArgs args(message); if (strchr(message, '$') == NULL) - throw ReFormatException(i18n("Missing placeholder: "), - message); + throw ReFormatException(i18n("Missing placeholder: "), message); args.arg(arg1); if (arg2 != NULL) args.arg(arg2); diff --git a/base/rebase.hpp b/base/rebase.hpp index 221c98b..d22d67b 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -30,8 +31,10 @@ # include # include # include -typedef u_int64_t uint64_t; -typedef u_int8_t uint8_t; + typedef u_int64_t uint64_t; + typedef u_int8_t uint8_t; + typedef __off_t ReFileSize_t; + typedef timespec ReFileTime_t; # define _strdup strdup # define _unlink unlink # define _strnicmp(s1, s2, n) strncasecmp(s1, s2, n) @@ -53,6 +56,8 @@ typedef u_int8_t uint8_t; typedef unsigned char uint8_t; typedef unsigned long uint32_t; typedef long int int32_t; + typedef int64_t ReFileSize_t; + typedef FILETIME ReFileTime_t; # define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0) # define ALLPERMS 0 # define _mkdir(name, mode) _mkdir(name) @@ -75,6 +80,6 @@ typedef u_int8_t uint8_t; #include "base/ReProgramArgs.hpp" typedef unsigned char byte_t; - +typedef int ReErrNo_t; #include "../base/baselocations.hpp" #endif /* REBASE_HPP_ */ diff --git a/cunit/cuReDirTools.cpp b/cunit/cuReDirTools.cpp index 6810241..578c223 100644 --- a/cunit/cuReDirTools.cpp +++ b/cunit/cuReDirTools.cpp @@ -61,6 +61,7 @@ private: void run(){ initTree(); + testTouch(); testDirStatistic(); testToolStatistic(); @@ -76,6 +77,9 @@ private: const char* argv[] = { "list", m_base.str(), NULL }; ReDirList().run(2, argv); } + int secOfFileTime(ReFileTime_t data){ + return data.tv_sec; + } void testCopyFile(){ #if defined __linux__ ReByteBuffer src(m_base); @@ -92,13 +96,12 @@ private: #endif } - void checkRelDate(time_t absTime, int relTime){ - int diff = int(time(NULL) - relTime - absTime); + void checkRelDate(ReFileTime_t absTime, int relTime){ + int diff = int(time(NULL) - relTime - secOfFileTime(absTime)); if (diff < 0) diff = - diff; checkT(diff < 2); } - void testDirOptions(){ class MyOptions : public ReDirOptions{ public: @@ -122,9 +125,10 @@ private: // local time: +3600 const int DIFF = 3600; - checkEqu(24*60*60 - DIFF, (int) opts.checkDate("1970.01.02")); - checkEqu(24*60*60+3600-DIFF, (int) opts.checkDate("1970.01.02/1")); - checkEqu(24*60*60 + 2*3600 + 33*60 - DIFF, (int) opts.checkDate("1970.01.02/02:33")); + const int tenYear = (365 * 10 + 2) * 24 * 3600; + checkEqu(tenYear + 24*60*60 - DIFF, secOfFileTime(opts.checkDate("1980.01.02"))); + checkEqu(tenYear + 24*60*60+3600-DIFF, secOfFileTime(opts.checkDate("1980.01.02/1"))); + checkEqu(tenYear + 24*60*60 + 2*3600 + 33*60 - DIFF, secOfFileTime(opts.checkDate("1980.01.02/02:33"))); checkRelDate(opts.checkDate("3m"), 3*60); checkRelDate(opts.checkDate("7h"), 7*60*60); checkRelDate(opts.checkDate("5d"), 5*24*60*60); @@ -142,7 +146,7 @@ private: void checkSetFilterFromProgramArgs(){ ReDirOptions opts(s_empty, s_empty); opts.addStandardFilterOptions(); - const char* argv[] = { "x", "-y1970.01.02", "-o1970.01.03", + const char* argv[] = { "x", "-y1980.01.02", "-o1980.01.03", "-D5", "-d1", "-z1k", "-Z2M", "-p;*;-*~" }; ReDirEntryFilter_t filter; @@ -150,8 +154,8 @@ private: opts.setFilterFromProgramArgs(filter); // local time: +3600 const int DIFF = 3600; - checkEqu(1*24*3600 - DIFF, (int) filter.m_maxAge); - checkEqu(2*24*3600 - DIFF, (int) filter.m_minAge); + checkEqu(1*24*3600 - DIFF, secOfFileTime(filter.m_maxAge)); + checkEqu(2*24*3600 - DIFF, secOfFileTime(filter.m_minAge)); checkEqu(5, (int) filter.m_maxDepth); checkEqu(1, (int) filter.m_minDepth); checkEqu(1000ll, filter.m_minSize); @@ -227,6 +231,55 @@ private: checkT(buffer.startsWith(" 0.000087 MB 5 6\t")); expected.set(m_base.str(), m_base.length()); } + /** + * Tests a file with a given context. + * + * @param filename name of the file to test + * @param content expected content: each line must contain a '*', + * separating the start of line and the end of line + */ + void checkFile(ReByteBuffer& filename, const char* content){ + ReStringList current; + current.readFromFile(filename.str()); + ReStringList expected; + expected.split(content, '\n'); + checkEqu(expected.count(), current.count()); + ReByteBuffer line; + ReStringList cols; + for (int ix = 0; ix < current.count(); ix++){ + line.setLength(0).append(current.strOf(ix), -1); + cols.split(expected.strOf(ix), '*'); + checkT(line.startsWith(cols.strOf(0))); + checkT(line.endsWith(cols.strOf(1))); + } + } + void testTouch(){ + ReByteBuffer nameCurrent; + buildFilename("current", nameCurrent); + ReByteBuffer optOutput("--output-file="); + optOutput.append(nameCurrent); + ReDirTools tools; + const char* argv[] = { "dt", "touch", "-P;*;-cache", "-tr", "-p;*.txt", + "-m2015.03.28/10:21:31", optOutput.str(), m_base.str(), NULL }; + tools.main(8, (char**) argv); + + checkFile(nameCurrent, + "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"); + + const char* argv2[] = { "dt", "list", "-P;*;-cache", "-tr", "-p;*.txt", + optOutput.str(), m_base.str(), NULL }; + tools.main(7, (char**) argv2); + + checkFile(nameCurrent, + " 0.000005 2015.03.28 10:21:31 02 *traverser/1.txt\n" + " 0.000027 2015.03.28 10:21:31 02 *traverser/dir1/dir1_2/dir1_2_1/x1.txt\n" + " 0.000027 2015.03.28 10:21:31 02 *traverser/dir1/dir1_2/dir1_2_1/x2.txt\n" + "=== 3 file(s) 0.000059 MByte 0 dirs(s) * sec"); + + } void testToolStatistic(){ ReDirTools tools; const char* argv[] = { "dt", "stat", "-P;*;-cache", m_base.str(), "2" }; diff --git a/cunit/cuReMD5.cpp b/cunit/cuReMD5.cpp index 9b32c4a..4bd88fc 100644 --- a/cunit/cuReMD5.cpp +++ b/cunit/cuReMD5.cpp @@ -116,7 +116,7 @@ private: int duration = milliSecSince(start); if (duration == 0) duration = 1; - printf("size: %.3f MiByte count: %d rate: %.3f MiB/sec duration: %s\n", + printf("size: %.1f MiByte count: %d rate: %.2f MiB/sec duration: %s\n", max / 1024.0 / 1024, passes, max / 1024.0 / 1024 * 1000 * passes / duration, ReByteBuffer("").appendMilliSec(duration).str()); diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp index 39b740a..0d21f1f 100644 --- a/cunit/cuReTraverser.cpp +++ b/cunit/cuReTraverser.cpp @@ -62,8 +62,6 @@ private: initTree(); testBasic(); - testDirOptions(); - checkSetFilterFromProgramArgs(); testList(); } void testList(){ @@ -93,66 +91,6 @@ private: checkT(diff < 2); } - void testDirOptions(){ - class MyOptions : public ReDirOptions{ - public: - MyOptions() : ReDirOptions(s_empty, s_empty) {} - public: - int count() { return m_countCompoundUsage; } - const char** usage() { return m_compoundUsage; } - }; - static const char* usage1[] = { "line1", "line2", NULL }; - static const char* usage2[] = { "x1", "x2", "x3", NULL }; - MyOptions opts; - opts.initCompoundUsage(sizeof usage1 + sizeof usage2); - opts.addCompoundUsage(usage1); - opts.addCompoundUsage(usage2); - checkEqu(7, opts.count()); - checkEqu("line1", opts.usage()[0]); - checkEqu("line2", opts.usage()[1]); - checkEqu("x1", opts.usage()[2]); - checkEqu("x2", opts.usage()[3]); - checkEqu("x3", opts.usage()[4]); - - // local time: +3600 - const int DIFF = 3600; - checkEqu(24*60*60 - DIFF, (int) opts.checkDate("1970.01.02")); - checkEqu(24*60*60+3600-DIFF, (int) opts.checkDate("1970.01.02/1")); - checkEqu(24*60*60 + 2*3600 + 33*60 - DIFF, (int) opts.checkDate("1970.01.02/02:33")); - checkRelDate(opts.checkDate("3m"), 3*60); - checkRelDate(opts.checkDate("7h"), 7*60*60); - checkRelDate(opts.checkDate("5d"), 5*24*60*60); - - checkEqu(125ll, opts.checkSize("125")); - checkEqu(125ll, opts.checkSize("125b")); - checkEqu(3000ll, opts.checkSize("3k")); - checkEqu(3*1024ll, opts.checkSize("3K")); - checkEqu(4*1000*1000ll, opts.checkSize("4m")); - checkEqu(4*1024*1024ll, opts.checkSize("4M")); - checkEqu(5*1000*1000*1000ll, opts.checkSize("5g")); - checkEqu(5*1024*1024*1024ll, opts.checkSize("5G")); - - } - void checkSetFilterFromProgramArgs(){ - ReDirOptions opts(s_empty, s_empty); - opts.addStandardFilterOptions(); - const char* argv[] = { "x", "-y1970.01.02", "-o1970.01.03", - "-D5", "-d1", "-z1k", "-Z2M", "-p;*;-*~" - }; - ReDirEntryFilter_t filter; - opts.programArgsChangeable().init(sizeof argv / sizeof argv[0], argv); - opts.setFilterFromProgramArgs(filter); - // local time: +3600 - const int DIFF = 3600; - checkEqu(1*24*3600 - DIFF, (int) filter.m_maxAge); - checkEqu(2*24*3600 - DIFF, (int) filter.m_minAge); - checkEqu(5, (int) filter.m_maxDepth); - checkEqu(1, (int) filter.m_minDepth); - checkEqu(1000ll, filter.m_minSize); - checkEqu(2*1024*1024ll, filter.m_maxSize); - checkNN(filter.m_nodePatterns); - checkEqu(";*;-*~", filter.m_nodePatterns->patternString()); - } void checkOneFile(const char* node, const char* parent, const ReHashList& hash){ ReByteBuffer path, expected; checkT(hash.get(ReByteBuffer(node), path)); diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index ee02528..0544b3b 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -22,6 +22,7 @@ enum LOCATION_DIRTOOL { LC_SET_PROPERTIES_1, // 50109 LC_SET_PROPERTIES_2, // 50110 LC_SET_PROPERTIES_3, // 50111 + LC_TOUCH_1, // 50112 }; const char* ReDirTools::m_version = "2015.02.04"; @@ -244,9 +245,9 @@ void ReDirOptions::addStandardFilterOptions(){ * @return the value converted into the absolute (or relative) time * @throws ReOptionExecption */ -time_t ReDirOptions::checkDate(const char* value){ +ReFileTime_t ReDirOptions::checkDate(const char* value){ ReByteBuffer theValue(value, -1); - time_t rc = 0; + time_t rcTime; if (theValue.count(".") == 2){ // a date: int year, month, day; @@ -259,9 +260,9 @@ time_t ReDirOptions::checkDate(const char* value){ case 5: case 6: { - if (year < 1970) + if (year < 1980) throw ReOptionException(&m_programArgs, - i18n("date < 1970.01.01: "), value); + i18n("date < 1980.01.01: $1"), value); struct tm time; memset(&time, 0, sizeof time); time.tm_year = year - 1900; @@ -269,12 +270,13 @@ time_t ReDirOptions::checkDate(const char* value){ time.tm_mday = day; time.tm_hour = hour; time.tm_min = minute; - rc = mktime(&time); + time.tm_sec = sec; + rcTime = mktime(&time); break; } default: throw ReOptionException(&m_programArgs, - i18n("invalid date/date-time value. yyyy.mm.dd/hh:MM expected"), value); + i18n("invalid date/date-time value: $1 yyyy.mm.dd/hh:MM expected"), value); } } else if (theValue.count(":") >= 1){ // a time: @@ -286,12 +288,12 @@ time_t ReDirOptions::checkDate(const char* value){ case 3: { // the time (today) - rc = time(NULL) / 86400 * 86400 + hour * 3600 + minute * 60 + sec; + rcTime = time(NULL) / 86400 * 86400 + hour * 3600 + minute * 60 + sec; break; } default: throw ReOptionException(&m_programArgs, - i18n("invalid time value. HH:MM:SS expected"), value); + i18n("invalid time value: $1. HH:MM:SS expected"), value); } } else { // a time distance value: @@ -299,7 +301,7 @@ time_t ReDirOptions::checkDate(const char* value){ int count = 0; int isNegative = false; if (theValue.startsWith("now")){ - rc = time(NULL); + rcTime = time(NULL); theValue.remove(0, 3); } if (theValue.str()[0] == '-') @@ -323,20 +325,22 @@ time_t ReDirOptions::checkDate(const char* value){ break; default: throw ReOptionException(&m_programArgs, - i18n("invalid unit. expected: s(econds) m(inutes) h(ours) d(ays)"), value); + i18n("invalid unit $1. expected: s(econds) m(inutes) h(ours) d(ays)"), value); } - rc = time(NULL) - count; + rcTime = time(NULL) - count; break; default: throw ReOptionException(&m_programArgs, - i18n("invalid relative time value expected. : s m h d"), + i18n("invalid relative time value $1 ( expected). : s m h d"), value); } if (isNegative) - rc -= count; + rcTime -= count; else - rc += count; + rcTime += count; } + ReFileTime_t rc; + ReDirStatus_t::timeToFiletime(rcTime, rc); return rc; } /** @@ -378,13 +382,13 @@ time_t ReDirOptions::checkSize(const char* value){ break; default: throw ReOptionException(&m_programArgs, - i18n("invalid . Expected: b k K m M g G"), + i18n("invalid : $1. Expected: b k K m M g G"), value); } break; default: throw ReOptionException(&m_programArgs, - i18n("invalid size value: : b k K m M g G"), + i18n("invalid size value: $1 expected: : b k K m M g G"), value); } return rc; @@ -663,7 +667,7 @@ bool ReTool::trace(const char* currentFile){ int duration = int(time(NULL) - m_startTime); buffer.appendInt(duration / 60).appendInt(duration % 60, ":%02d: "); buffer.appendInt(m_files).append("/", 1).appendInt(m_traverser.directories()).append(" dir(s)"); - buffer.appendInt(m_files).append("/", 1).appendInt(m_traverser.files()).append(" dir(s)"); + buffer.appendInt(m_files).append("/", 1).appendInt(m_traverser.files()).append(" file(s)"); buffer.append(currentFile); fputs(buffer.str(), stdout); return true; @@ -768,10 +772,14 @@ void ReTool::processTree(const char* directory){ ReDirStatus_t* entry; int level; while( (entry = m_traverser.nextFile(level, &m_filter)) != NULL){ - if (entry->isDirectory()) + if (entry->isDirectory()){ processDir(entry); - else + m_directories++; + } else { processFile(entry); + m_files++; + m_sizes += entry->fileSize(); + } } } /** @@ -784,6 +792,19 @@ void ReTool::processTree(const char* directory){ void ReTool::processFile(ReDirStatus_t* entry){ fprintf(m_output, "+++ ignored (not a directory): %s\n", entry->fullName()); } +/** + * Issues a summary message if verbose level allows this. + */ +void ReTool::printSummary(){ + if (m_verboseLevel >= V_SUMMARY){ + int duration = int(time(NULL) - m_start); + ReByteBuffer line; + statisticAsString(line); + line.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec")); + fprintf(m_output, "=== %s\n", line.str()); + } + +} /** * Processes one directory. * @@ -968,7 +989,7 @@ void ReDirBatch::doIt(){ #elif defined __WIN32__ const char* prefix = "rem"; #endif - toString(buffer); + statisticAsString(buffer); buffer.append(" ").appendTime(duration); fprintf(m_output, "%s %s\n", buffer.str()); } @@ -1030,8 +1051,8 @@ void ReDirList::doIt(){ if (m_verboseLevel >= V_SUMMARY){ int duration = int(time(NULL) - m_start); ReByteBuffer line; - toString(line); - line.appendTime(duration).append(" ", 1).append(i18n("sec")); + statisticAsString(line); + line.append(" ", 1).appendTime(duration).append(" ", 1).append(i18n("sec")); fprintf(m_output, "=== %s\n", line.str()); } } @@ -1091,7 +1112,7 @@ const ReStringList& ReDirStatistic::calculate(const char* base, int level, current->m_path.set(base, -1); ReByteBuffer line; bool useFilter = filter.m_minSize > 0 || filter.m_maxSize != -1 - || filter.m_minAge != 0 || filter.m_maxAge != 0 + || ! filetimeIsUndefined(filter.m_minAge) || ! filetimeIsUndefined(filter.m_maxAge) || m_nodePatterns.count() > 0; while( (entry = traverser.rawNextFile(currentDepth))){ if (currentDepth <= level && ! entry->m_path.equals(current->m_path)){ @@ -1226,10 +1247,13 @@ void formatWithSizeFilesAndDirs(const ReDirStatisticData& data, * Constructor. */ ReDirTouch::ReDirTouch() : - ReTool(s_touchUsage, s_touchExamples, 2, 1, 0, false), - m_buffer(), - m_properties() + ReTool(s_touchUsage, s_touchExamples, 1, 0, 0, false), + m_buffer() + //m_modified() + //m_accessed() { + setFiletimeUndef(m_modified); + setFiletimeUndef(m_accessed); // standard short options: D d O o P p T t v y Z z m_programArgs.addString("accessed", i18n("the new access time.\n" @@ -1256,21 +1280,98 @@ void ReDirTouch::doIt(){ m_modified = checkDate(buffer.str()); if (m_programArgs.getString("accessed", buffer)[0] != '\0') m_accessed = checkDate(buffer.str()); + if (filetimeIsUndefined(m_modified) && filetimeIsUndefined(m_accessed)) + help("missing --modified and/or --accessed"); processFileArguments(); - if (m_verboseLevel >= V_SUMMARY){ - int duration = int(time(NULL) - m_start); - ReByteBuffer line; - toString(line); - line.appendTime(duration).append(" ", 1).append(i18n("sec")); - fprintf(m_output, "=== %s\n", line.str()); - } + printSummary(); } +/** + * Processes one directory. + * + * @param entry the properties of the directory to process + */ void ReDirTouch::processDir(ReDirStatus_t* entry){ processFile(entry); } -void ReDirTouch::processFile(ReDirStatus_t* entry){ +static bool isAbsoluteTime(ReFileTime_t& time){ + 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__ +#endif +} +static void addRelativeTime(ReFileTime_t& absTime, const ReFileTime_t& relTime){ +#if defined __linux__ + if ( (absTime.tv_nsec += relTime.tv_nsec) >= 1000*1000*1000){ + absTime.tv_nsec -= 1000*1000*1000; + absTime.tv_sec += 1; + } + absTime.tv_sec += relTime.tv_sec; +#elif defined __WIN32__ +#endif + +} +/** + * Processes one file. + * + * @param entry the properties of the file to process + */ +void ReDirTouch::processFile(ReDirStatus_t* entry){ + ReFileTime_t modified = *entry->modified(); + int countTimes = 0; + if (! filetimeIsUndefined(m_modified)){ + countTimes++; + if (isAbsoluteTime(m_modified)) + modified = m_modified; + else + addRelativeTime(modified, m_modified); + } + ReFileTime_t accessed = *entry->accessed(); + if (! filetimeIsUndefined(m_accessed)){ + countTimes++; + if (isAbsoluteTime(m_accessed)) + accessed = m_accessed; + else + addRelativeTime(accessed, m_accessed); + } + const char* name = entry->fullName(); + if (touch(name, modified, accessed, ReLogger::globalLogger()) == 0 + && m_verboseLevel >= V_NORMAL){ + ReByteBuffer bufferTime; + ReByteBuffer bufferTime2; + if (m_verboseLevel == V_NORMAL){ + if (countTimes == 2) + fprintf(m_output, "%s | %s | %s\n", + ReDirStatus_t::filetimeToString(&modified, bufferTime), + ReDirStatus_t::filetimeToString(&accessed, bufferTime2), + name); + else { + ReDirStatus_t::filetimeToString( + filetimeIsUndefined(m_modified) ? &accessed : &modified, + bufferTime); + fprintf(m_output, "%s %s\n", bufferTime.str(), name); + } + } else { + ReByteBuffer bufferTime3; + ReByteBuffer bufferTime4; + if (countTimes == 2) + fprintf(m_output, "%s -> %s | %s -> %s | %s\n", + ReDirStatus_t::filetimeToString(entry->modified(), bufferTime), + ReDirStatus_t::filetimeToString(&modified, bufferTime2), + ReDirStatus_t::filetimeToString(entry->accessed(), bufferTime3), + ReDirStatus_t::filetimeToString(&accessed, bufferTime4), + name); + else { + ReDirStatus_t::filetimeToString( + filetimeIsUndefined(m_modified) ? &m_accessed : &m_modified, + bufferTime); + fprintf(m_output, "%s -> %s %s\n", bufferTime.str(), name); + } + } + } } /** @@ -1280,8 +1381,34 @@ void ReDirTouch::processFile(ReDirStatus_t* entry){ * @param properties contains modification and access time * @param logger NULL or the logger */ -bool ReDirTouch::touch(const char* filename, ReFileProperties_t* properties, - ReLogger* logger){ +ReErrNo_t ReDirTouch::touch(const char* filename, const ReFileTime_t& modified, + const ReFileTime_t& accessed, ReLogger* logger){ +#if defined __linux__ + timeval times[2]; + times[0].tv_sec = accessed.tv_sec; + times[0].tv_usec = accessed.tv_nsec / 1000; + times[1].tv_sec = modified.tv_sec; + times[1].tv_usec = modified.tv_nsec / 1000; + ReErrNo_t rc = utimes(filename, times) == 0 ? 0 : errno; + +#elif defined __WIN32__ + ReErrNo_t rc = 0; + HANDLE handle = CreateFile(filename, FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == UNDEF_HANDLE) + rc = GetLastError(); + else { + if (SetFileTime(handle, (LPFILETIME) NULL,(LPFILETIME) NULL,&thefiletime) != 0) + rc = GetLastError(); + CloseHandle(handle); + } +#endif + if (rc != 0 && logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_TOUCH_1, + i18n("cannot change filetime: $1 (errno: $2)")).arg(filename) + .arg(errno).end(); + return rc; } @@ -1413,7 +1540,7 @@ bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties, else { if (logger != NULL) logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_1, - i18n("could not find: $ (errno: $2)")).arg(source) + i18n("could not find: $1 (errno: $2)")).arg(source) .arg(errno).end(); } } @@ -1424,7 +1551,7 @@ bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties, i18n("cannot open $1 (errno: $2)")) .arg(source).arg(errno).end(); } else { - FileSize_t size = properties == NULL ? 0x7fffffff : properties->st_size; + ReFileSize_t size = properties == NULL ? 0x7fffffff : properties->st_size; FILE* fpTarget = fopen(target, "w"); if (fpTarget == NULL){ if (logger != NULL) @@ -1483,10 +1610,12 @@ bool ReDirSync::setProperties(const char* fullName, ReFileProperties_t* properties, ReLogger* logger){ bool rc = true; #if defined __linux__ - struct utimbuf times; - times.actime = properties->st_atime; - times.modtime = properties->st_mtime; - if (utime(fullName, ×) != 0){ + timeval times[2]; + times[0].tv_sec = properties->st_atim.tv_sec; + times[0].tv_usec = properties->st_atim.tv_nsec / 1000; + times[1].tv_sec = properties->st_mtim.tv_sec; + times[1].tv_usec = properties->st_mtim.tv_nsec / 1000; + if (utimes(fullName, times) != 0){ if (logger != NULL) logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_PROPERTIES_1, i18n("cannot change file times: $1 (errno: $2)")) diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 87a49ca..259f415 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -26,7 +26,7 @@ public: public: void addCompoundUsage(const char** usage); void addStandardFilterOptions(); - time_t checkDate(const char* value); + ReFileTime_t checkDate(const char* value); const char* checkPatternList(const char* value); int64_t checkSize(const char* value); void checkStandardFilterOptions(); @@ -89,6 +89,7 @@ protected: * Normally it calls processFileArguments() after some initializations. */ virtual void doIt() = 0; + void printSummary(); virtual void processDir(ReDirStatus_t* status); virtual void processFile(ReDirStatus_t* status); void processFileArguments(); @@ -201,13 +202,12 @@ protected: virtual void processDir(ReDirStatus_t* entry); virtual void processFile(ReDirStatus_t* entry); public: - static bool touch(const char* filename, ReFileProperties_t* properties, - ReLogger* logger = NULL); + static ReErrNo_t touch(const char* filename, const ReFileTime_t& modified, + const ReFileTime_t& accessed, ReLogger* logger = NULL); protected: ReByteBuffer m_buffer; - time_t m_modified; - time_t m_accessed; - ReFileProperties_t m_properties; + ReFileTime_t m_modified; + ReFileTime_t m_accessed; }; diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index 6513a80..30004cf 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -85,11 +85,7 @@ const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer) { * @return buffer.str() (for chaining) */ const char* ReDirStatus_t::filetimeAsString(ReByteBuffer& buffer) { - time_t time1 = filetimeToTime(modified()); - struct tm* time2 = gmtime(&time1); - buffer.setLength(4+2*2+2*2+1+3*2+2*1); - strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2); - return buffer.str(); + return filetimeToString(modified(), buffer); } @@ -258,7 +254,7 @@ bool ReDirStatus_t::isRegular() { * * @return the filesize */ -FileSize_t ReDirStatus_t::fileSize() { +ReFileSize_t ReDirStatus_t::fileSize() { #ifdef __linux__ return getStatus()->st_size; #elif defined __WIN32__ @@ -270,9 +266,9 @@ FileSize_t ReDirStatus_t::fileSize() { * * @return the modification time */ -const FileTime_t* ReDirStatus_t::modified() { +const ReFileTime_t* ReDirStatus_t::modified() { #ifdef __linux__ - return &(getStatus()->st_mtime); + return &(getStatus()->st_mtim); #elif defined __WIN32__ return &m_data.ftLastWriteTime; #endif @@ -283,17 +279,38 @@ const FileTime_t* ReDirStatus_t::modified() { * * @return the last access time */ -const FileTime_t* ReDirStatus_t::accessed() { +const ReFileTime_t* ReDirStatus_t::accessed() { #ifdef __linux__ - return &(getStatus()->st_atime); + return &(getStatus()->st_atim); #elif defined __WIN32__ return &m_data.ftLastAccessTime; #endif } -time_t ReDirStatus_t::filetimeToTime(const FileTime_t* filetime){ +/** + * Converts a filetime to a string. + * + * @param time the filetime to convert + * @param buffer OUT: the buffer for the string + * @return buffer.str(), e.g. "2014.01.07 02:59:43" + */ +const char* ReDirStatus_t::filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer){ + time_t time1 = filetimeToTime(time); + struct tm* time2 = localtime(&time1); + buffer.setLength(4+2*2+2*2+1+3*2+2*1); + strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2); + return buffer.str(); +} + +/** + * Converts a filetime to a unix time (seconds since the Epoche). + * + * @param filetime the filetime to convert + * @return the count of seconds since 1.1.1970 + */ +time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime){ #ifdef __linux__ - return *filetime; + return filetime->tv_sec; #elif defined __WIN32__ // takes the last modified date LARGE_INTEGER date, adjust; @@ -313,9 +330,10 @@ time_t ReDirStatus_t::filetimeToTime(const FileTime_t* filetime){ * @param time the unix time (secondes since 1.1.1970) * @param filetime OUT: the OS specific filetime */ -void ReDirStatus_t::timeToFiletime(time_t time, FileTime_t& filetime){ +void ReDirStatus_t::timeToFiletime(time_t time, ReFileTime_t& filetime){ #ifdef __linux__ - filetime = time; + filetime.tv_sec = time; + filetime.tv_nsec = 0; #elif defined __WIN32__ LONGLONG ll = Int32x32To64(time, 10000000) + 116444736000000000; filetime.dwLowDateTime = (DWORD)ll; @@ -332,11 +350,13 @@ ReDirEntryFilter_t::ReDirEntryFilter_t() : m_pathPatterns(NULL), m_minSize(0), m_maxSize(-1), - m_minAge(0), - m_maxAge(0), + //m_minAge(0), + //m_maxAge(0), m_minDepth(0), m_maxDepth(512) { + setFiletimeUndef(m_minAge); + setFiletimeUndef(m_maxAge); } /** @@ -357,9 +377,9 @@ bool ReDirEntryFilter_t::match(ReDirStatus_t& entry){ break; if (m_maxSize >= 0 && size > m_maxSize) break; - if (m_minAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) > m_minAge) + if (! filetimeIsUndefined(m_minAge) && *entry.modified() > m_minAge) break; - if (m_maxAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) < m_maxAge) + if (! filetimeIsUndefined(m_maxAge) && m_maxAge > *entry.modified()) break; const char* node = entry.node(); if (m_nodePatterns != NULL && ! m_nodePatterns->match(node)) @@ -404,7 +424,7 @@ ReDirTreeStatistic::ReDirTreeStatistic() : * @param formatFiles the sprintf format for the directory count, e.g. "%6d" * @return a human readable string */ -const char* ReDirTreeStatistic::toString(ReByteBuffer& buffer, bool append, +const char* ReDirTreeStatistic::statisticAsString(ReByteBuffer& buffer, bool append, const char* formatFiles, const char* formatSizes, const char* formatDirs) { if (! append) diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp index 5057674..2b967f5 100644 --- a/os/ReTraverser.hpp +++ b/os/ReTraverser.hpp @@ -16,12 +16,27 @@ #include typedef DIR* FindFileHandle_t; -typedef __off_t FileSize_t; -typedef time_t FileTime_t; -#else -typedef int64_t FileSize_t; -typedef FILETIME FileTime_t; #endif +/** Returns whether a filetime is undefined. + * @param time the filetime to test + * @return true: the given filetime is undefined + */ +inline bool filetimeIsUndefined(ReFileTime_t& time){ +#if defined __linux__ + return time.tv_sec == 0 && time.tv_nsec == 0; +#elif defined __WIN32__ +#endif +} +/** Sets the filetime to undefined. + * @param time the filetime to clear + */ +inline void setFiletimeUndef(ReFileTime_t& time){ +#if defined __linux__ + time.tv_sec = time.tv_nsec = 0; +#elif defined __WIN32__ +#endif +} + class ReDirStatus_t{ public: enum Type_t { @@ -54,9 +69,9 @@ public: bool isDirectory(); bool isLink(); bool isRegular(); - FileSize_t fileSize(); - const FileTime_t* modified(); - const FileTime_t* accessed(); + ReFileSize_t fileSize(); + const ReFileTime_t* modified(); + const ReFileTime_t* accessed(); bool isDotDir() const; const char* rightsAsString(ReByteBuffer& buffer); const char* filetimeAsString(ReByteBuffer& buffer); @@ -76,8 +91,9 @@ public: WIN32_FIND_DATAA m_data; #endif public: - static time_t filetimeToTime(const FileTime_t* time); - static void timeToFiletime(time_t time, FileTime_t& filetime); + static time_t filetimeToTime(const ReFileTime_t* time); + static void timeToFiletime(time_t time, ReFileTime_t& filetime); + static const char* filetimeToString(const ReFileTime_t* time, ReByteBuffer& buffer); }; class ReDirEntryFilter_t{ public: @@ -89,10 +105,10 @@ public: ReDirStatus_t::Type_t m_types; RePatternList* m_nodePatterns; RePatternList* m_pathPatterns; - FileSize_t m_minSize; - FileSize_t m_maxSize; - time_t m_minAge; - time_t m_maxAge; + ReFileSize_t m_minSize; + ReFileSize_t m_maxSize; + ReFileTime_t m_minAge; + ReFileTime_t m_maxAge; int m_minDepth; int m_maxDepth; }; @@ -135,9 +151,9 @@ class ReDirTreeStatistic { public: ReDirTreeStatistic(); public: - const char* toString(ReByteBuffer& buffer, bool append = false, - const char* formatFiles = "%8d", const char* formatSizes = "%12.6f", - const char* formatDirs = "%7d"); + const char* statisticAsString(ReByteBuffer& buffer, bool append = false, + const char* formatFiles = "%8d ", const char* formatSizes = "%12.6f", + const char* formatDirs = "%7d "); /** * Resets the counters. */ diff --git a/os/reos.hpp b/os/reos.hpp index 696bdae..f9aeaf4 100644 --- a/os/reos.hpp +++ b/os/reos.hpp @@ -13,7 +13,6 @@ #if defined __linux__ #include "unistd.h" #include -#include #elif defined __WIN32__ #include #include "windows.h" @@ -22,6 +21,17 @@ #error "unknown os" #endif +/** Returns whether a time is greater (younger) than another. + * @param time1 first operand + * @param time2 second operand + * @return true: time1 > time2 + */ +inline bool operator >(const ReFileTime_t& time1, const ReFileTime_t& time2){ +#if defined __linux__ + return time1.tv_sec > time1.tv_sec || time1.tv_sec == time2.tv_sec && time1.tv_nsec > time2.tv_nsec; +#else +#endif +} #include "os/ReTraverser.hpp" #include "os/ReDirTools.hpp"