From: kawi Date: Sun, 4 Jan 2015 13:56:04 +0000 (+0100) Subject: dirtool list works X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=3aa2ef97c9036c101a7a529116f111a427de1d1a;p=crepublib dirtool list works --- diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp index ce7d449..ba9d8d1 100644 --- a/base/ReProgramArgs.cpp +++ b/base/ReProgramArgs.cpp @@ -13,7 +13,9 @@ * @param caller The object which throw the exception. * @param message The error message with one or two placeholders. * @param arg1 The first argument (for the first placeholder). - * @param arg2 The 2nd argument (for the 2nd placeholder). If NULL only one placeholder exists. + * @param arg2 The 2nd argument (for the 2nd placeholder). + * If NULL only one placeholder exists. + * @throws ReFormatException */ ReOptionException::ReOptionException(ReProgramArgs* caller, const char* message, const char* arg1, const char* arg2) @@ -21,10 +23,13 @@ ReOptionException::ReOptionException(ReProgramArgs* caller, const char* message, ReException() { ReVarArgs args(message); + if (strchr(message, '$') == NULL) + throw ReFormatException(i18n("Missing placeholder: "), + message); args.arg(arg1); if (arg2 != NULL) args.arg(arg2); - setMessage(args.asCString()); + setMessage(args.asCString()); if (caller != NULL) caller->setLastError(args.asCString()); } diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index 28a707a..0989152 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -24,12 +24,14 @@ static const char* s_standardFilterUsage[] = { " is a date (e.g. 2015.02.17) or number followed by an unit", " units: m(inutes) h(hours), d(days). Default: m(inutes)", " examples: -o25 --older-than=30d -o24h -o2009.3.2/12:00 -o1999.01.01", + "-q or --quiet", + " no additional information like runtime", "-P

or --pathname-pattern=

", " a list of patterns for the path (without basename) separated by ';'", " Each pattern can contain '*' as wildcard", " If the first character is '^' the pattern is a 'not pattern':" - " A directory will be entered if at least one of the positive patterns and none", - " of the 'not patterns' matches", + " A directory will be entered if at least one of the positive patterns", + " and none of the 'not patterns' matches", " examples: '*;^*/.git/' '*/cache/;*/temp/", "-p

or --basename-pattern=

", " a list of patterns for the basename (filename without path) separated by ';'", @@ -38,11 +40,16 @@ static const char* s_standardFilterUsage[] = { " A file will be found if at least one of the positive patterns and none", " of the 'not patterns' matches", " examples: '*.cpp;*.hpp;Make*' '*;^*.bak;^*~", + "-t or --trace-interval= Default: 0", + " all seconds the current path will be traced", + " 0: no trace", "-t or --type=", " the file type", " is a list of values:", - " : d(irectory) f(file) r(egular file) l(ink)", - " examples: -td --type=dr", + " : b(lock) c(har) d(irectory) (l)i(nkdir) l(ink) o(ther)", + " p(ipe) s(ocket) r(egular)", + " -sets: S(pecial)=bcspo N(ondir)=Slr", + " examples: -td --type=dr -tNi", "-y or --younger-than=", " the modification date is younger than ", " is a date (e.g. 2015.02.17) or number followed by an unit", @@ -164,12 +171,14 @@ void ReDirOptions::addStandardFilterOptions(){ m_programArgs.addInt("maxdepth", "maximal subdir depth", 'D', "max-depth", 512); m_programArgs.addInt("mindepth", "minimal subdir depth", 'd', "min-depth", 512); m_programArgs.addString("older", "older than", 'o', "older-than", false, NULL); - m_programArgs.addString("type", "file type", 't', "type", false, "df"); + m_programArgs.addString("nodepattern", "pattern list for the basename", 'p', "basename-pattern", false, NULL); + m_programArgs.addString("pathpattern", "pattern list for the path", 'P', "path-pattern", false, NULL); + m_programArgs.addBool("quiet", "suppress additional info", 'q', "quiet", false); + m_programArgs.addInt("trace", "trace interval", 'T', "trace-interval", 0); + m_programArgs.addString("type", "file type", 't', "type", false, NULL); m_programArgs.addString("younger", "younger than", 'y', "younger-than", false, NULL); m_programArgs.addString("maxsize", "maximal filesize", 'Z', "max-size", false, NULL); m_programArgs.addString("minsize", "minimal filesize", 'z', "min-size", false, NULL); - m_programArgs.addString("nodepattern", "pattern list for the basename", 'p', "basename-pattern", false, NULL); - m_programArgs.addString("pathpattern", "pattern list for the path", 'P', "path-pattern", false, NULL); } /** @@ -282,17 +291,75 @@ 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 . Expected: b k K m M g G"), value); } break; default: throw ReOptionException(&m_programArgs, - i18n("invalid size value: expected. : b k K m M g G"), + i18n("invalid size value: : b k K m M g G"), value); } return rc; } +/** + * Checks whether the given value is a valid filetype list. + * + * @param value value to check + * @return the bitmask + * @throws ReOptionExecption + */ +ReDirStatus_t::Type_t ReDirOptions::checkType(const char* value){ + int rc = ReDirStatus_t::TF_UNDEF; + while (*value != '\0'){ + switch(*value){ + case 'b': + rc |= ReDirStatus_t::TF_BLOCK; + break; + case 'c': + rc |= ReDirStatus_t::TF_CHAR; + break; + case 'd': + rc |= ReDirStatus_t::TF_SUBDIR; + break; + case 'i': + rc |= ReDirStatus_t::TF_LINK_DIR; + break; + case 'l': + rc |= ReDirStatus_t::TF_LINK; + break; + case 'o': + rc |= ReDirStatus_t::TF_OTHER; + break; + case 'p': + rc |= ReDirStatus_t::TF_PIPE; + break; + case 's': + rc |= ReDirStatus_t::TF_SOCKET; + break; + case 'r': + rc |= ReDirStatus_t::TF_REGULAR; + break; + case 'S': + rc |= ReDirStatus_t::TC_SPECIAL; + break; + case 'N': + rc |= ReDirStatus_t::TC_NON_DIR; + break; + case ' ': + case ',': + break; + default: + throw ReOptionException(&m_programArgs, + i18n("invalid type: $1 Expected: b(lock) c(har) d(irectory)" + " (l)i(nkdir) l(ink) o(ther) p(ipe) s(ocket) r(egular)" + " S(pecial=bcspo) N(ondir=Slr)"), + value); + } + value++; + } + return (ReDirStatus_t::Type_t) rc; +} /** * Sets the standard filter options given by the program arguments. @@ -309,6 +376,8 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter_t& filter){ filter.m_maxSize = checkSize(buffer.str()); if (m_programArgs.getString("minsize", buffer)[0] != '\0') filter.m_minSize = checkSize(buffer.str()); + if (m_programArgs.getString("type", buffer)[0] != '\0') + filter.m_types = checkType(buffer.str()); filter.m_minDepth = m_programArgs.getInt("mindepth"); filter.m_maxDepth = m_programArgs.getInt("maxdepth"); if (m_programArgs.getString("nodepattern", buffer) != NULL){ @@ -319,6 +388,7 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter_t& filter){ m_pathPatterns.set(buffer.str()); filter.m_pathPatterns = &m_nodePatterns; } + filter.m_traceInterval = m_programArgs.getInt("trace"); } /** * Prints a help message, the error message and exits. @@ -343,11 +413,7 @@ void ReDirOptions::checkStandardFilterOptions(){ ReByteBuffer buffer; checkDate(m_programArgs.getString("older", buffer)); checkDate(m_programArgs.getString("younger", buffer)); - const char* value = m_programArgs.getString("type", buffer); - if (strspn (value, "dfrl") != strlen(value)) - throw ReOptionException(&m_programArgs, - i18n("unknown file type. Expected: d(irectory) f(file) r(egular file) l(ink)"), - value); + checkType(m_programArgs.getString("types", buffer)); checkSize(m_programArgs.getString("maxsize", buffer)); checkSize(m_programArgs.getString("minsize", buffer)); } @@ -610,12 +676,17 @@ ReDirList::ReDirList() : void ReDirList::list(int argc, char* argv[]){ ReDirEntryFilter_t filter; try { + time_t start = time(NULL); m_programArgs.init(argc, argv); + bool verbose = ! m_programArgs.getBool("quiet"); setFilterFromProgramArgs(filter); if (m_programArgs.getArgCount() == 0) help(i18n("no arguments given (missing path)")); ReByteBuffer bufferRights; ReByteBuffer bufferTime; + int64_t sumSizes = 0; + int files = 0; + int dirs = 0; for (int ix = 0; ix < m_programArgs.getArgCount(); ix++){ ReTraverser traverser(m_programArgs.getArg(ix)); traverser.setMinLevel(filter.m_maxDepth); @@ -623,13 +694,25 @@ void ReDirList::list(int argc, char* argv[]){ int level; ReDirStatus_t* entry; while( (entry = traverser.nextFile(level, &filter)) != NULL){ + if (entry->isDirectory()) + dirs++; + else{ + files++; + sumSizes += entry->fileSize(); + } if (! printOneFile(entry)) - printf("%s %12lld %s %s%s\n", - entry->rightsAsString(bufferRights), entry->fileSize(), + printf("%s %12.6f %s %02x %s%s\n", + entry->rightsAsString(bufferRights), entry->fileSize() / 1E6, entry->filetimeAsString(bufferTime), + entry->type(), entry->m_path.str(), entry->node()); } } + if (verbose){ + int duration = int(time(NULL) - start); + printf ("+++ %d dirs and %d file(s) with %.6f MByte in %02d:%02d sec\n", + dirs, files, sumSizes / 1E6, duration / 60, duration % 60); + } } catch(ReOptionException& exc){ help(exc.getMessage()); } diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 53d4e7d..7e1b2fd 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -23,6 +23,7 @@ public: { return m_programArgs; } time_t checkDate(const char* value); int64_t checkSize(const char* value); + ReDirStatus_t::Type_t checkType(const char* value); void setFilterFromProgramArgs(ReDirEntryFilter_t& filter); void help(const char* errorMessage, const char* message2 = NULL); protected: diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index f2f9d14..22f81b1 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -88,11 +88,13 @@ const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer) { */ const char* ReDirStatus_t::filetimeAsString(ReByteBuffer& buffer) { time_t time1 = filetimeToTime(modified()); - struct tm* time2 = localtime(&time1); - buffer.setLength(4+2*1+2*2+1+3*2+2*1); - strftime(buffer.buffer(), buffer.length(), "%y.%m.%d %H:%M:%S", time2); + 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(); } + + /** * Tests whether the instance contains data about "." or "..". * @@ -145,6 +147,40 @@ bool ReDirStatus_t::findNext(){ #endif return rc; } + +/** + * Returns the type of the entry. + * return the file type, e.g. TF_REGULAR + */ +ReDirStatus_t::Type_t ReDirStatus_t::type(){ + Type_t rc = TF_UNDEF; +#if defined __linux__ +#elif defined __WIN32__ + int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY + | FILE_ATTRIBUTE_HIDDEN + | FILE_ATTRIBUTE_SYSTEM + | FILE_ATTRIBUTE_ARCHIVE + | FILE_ATTRIBUTE_NORMAL + | FILE_ATTRIBUTE_TEMPORARY + | FILE_ATTRIBUTE_SPARSE_FILE + | FILE_ATTRIBUTE_COMPRESSED + | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED + | FILE_ATTRIBUTE_ENCRYPTED + | FILE_ATTRIBUTE_HIDDEN)); + + if (0 == flags) + rc = TF_REGULAR; + else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){ + rc = (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + ? TF_LINK_DIR : TF_SUBDIR; + } else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + rc = TF_LINK; + else + rc = TF_OTHER; +#endif + return rc; +} + /** * Tests whether the instance is a directory. * @@ -182,7 +218,7 @@ bool ReDirStatus_t::isRegular() { #ifdef __linux__ return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_REG) || S_ISREG(getStatus()->st_mode); #elif defined __WIN32__ - return 0 != (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); + return 0 == (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); #endif } /** @@ -246,9 +282,7 @@ void ReDirStatus_t::timeToFiletime(time_t time, FileTime_t& filetime){ * Constructor. */ ReDirEntryFilter_t::ReDirEntryFilter_t() : - m_regulars(true), - m_specials(true), - m_directories(true), + m_types(ReDirStatus_t::TC_ALL), m_nodePatterns(), m_pathPatterns(), m_minSize(0), @@ -256,7 +290,10 @@ ReDirEntryFilter_t::ReDirEntryFilter_t() : m_minAge(0), m_maxAge(0), m_minDepth(0), - m_maxDepth(512) + m_maxDepth(512), + m_traceInterval(0), + m_lastTrace(0), + m_traceCounter(0) { } @@ -271,11 +308,14 @@ ReDirEntryFilter_t::~ReDirEntryFilter_t(){ bool ReDirEntryFilter_t::match(ReDirStatus_t& entry){ bool rc = false; do { - if (! m_directories && entry.isDirectory()) - break; - if (m_specials && (entry.isDirectory() || entry.isRegular())) - break; - if (m_regulars && ! entry.isRegular()) + if (m_traceCounter++ % 100 == 0 && m_traceInterval > 0){ + time_t now = time(NULL); + if (int(now - m_lastTrace) > m_traceInterval){ + m_lastTrace = now; + fprintf(stderr, "%s%s\n", entry.m_path.str(), entry.node()); + } + } + if (0 == (entry.type() & m_types)) break; if (m_minSize > 0 && entry.fileSize() > m_minSize) break; diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp index d817327..6e76316 100644 --- a/os/ReTraverser.hpp +++ b/os/ReTraverser.hpp @@ -21,6 +21,25 @@ typedef int64_t FileSize_t; typedef FILETIME FileTime_t; #endif class ReDirStatus_t{ +public: + enum Type_t { + TF_UNDEF = 0, + // single property flags: + TF_SUBDIR = 1 << 0, + TF_REGULAR = 1 << 1, + TF_LINK = 1 << 2, + TF_LINK_DIR = 1 << 3, + TF_BLOCK = 1 << 4, + TF_PIPE = 1 << 5, + TF_CHAR = 1 << 6, + TF_SOCKET = 1 << 7, + TF_OTHER = 1 << 8, + // collections: + TC_SPECIAL = (TF_BLOCK | TF_CHAR | TF_SOCKET | TF_PIPE | TF_OTHER), + TC_NON_DIR = (TC_SPECIAL | TF_LINK | TF_REGULAR), + TC_ALL = (TF_SUBDIR | TC_NON_DIR | TF_LINK_DIR) + }; + public: ReDirStatus_t(); public: @@ -37,6 +56,7 @@ public: bool isDotDir() const; const char* rightsAsString(ReByteBuffer& buffer); const char* filetimeAsString(ReByteBuffer& buffer); + Type_t type(); public: ReByteBuffer m_path; int m_passNo; @@ -61,9 +81,7 @@ public: public: bool match(ReDirStatus_t& entry); public: - bool m_regulars; - bool m_specials; - bool m_directories; + ReDirStatus_t::Type_t m_types; RePatternList* m_nodePatterns; RePatternList* m_pathPatterns; FileSize_t m_minSize; @@ -72,6 +90,9 @@ public: time_t m_maxAge; int m_minDepth; int m_maxDepth; + int m_traceInterval; + time_t m_lastTrace; + int m_traceCounter; }; #define MAX_ENTRY_STACK_DEPTH 256 class ReTraverser {