From 0b1c1f2bb2e6a1d57f13b99ee6776c0e61e48976 Mon Sep 17 00:00:00 2001 From: kawi Date: Mon, 5 Jan 2015 15:25:34 +0100 Subject: [PATCH] dirtools sync --- os/ReDirTools.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++++++ os/ReDirTools.hpp | 20 +++++-- 2 files changed, 154 insertions(+), 6 deletions(-) diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index 0a7e61b..3c746da 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -21,6 +21,7 @@ static const char* s_helpSummary[] = { "help shows info about the arguments/options", "list shows the meta data of the selected files", "statistic shows statistics about a direcctory tree", + "synchronize adapts the content of a directory tree to another", NULL }; @@ -69,6 +70,23 @@ const char* s_statisticExamples[] = { NULL }; +const char* s_syncUsage[] = { + ":", + "sy(nchronize) [ ...] ", + " Synchronizes the content of a directory tree with another.", + " Newer or missing files will be copied", + " If a source name ends with the separator (/ in linux, \\ in win) the target", + " will be completed with the basename of the source.", + " Example:", + " 'sync home backup' copies the file home/x.txt to backup/home/x.txt", + " 'sync data/ backup/data2' copies the file home/x.txt to backup/data2/x.txt", + NULL +}; +const char* s_syncExamples[] = { + "dirtool sync --basename-pattern=;*.txt;*.doc e:\\data\\ d:\\backup\\data2", + "dirtool sync --type=r --max-size=1G usr etc /media/backup", + NULL +}; /** * Constructor. @@ -949,6 +967,128 @@ void ReDirBatch::createBatch(int argc, char* argv[]){ } } +/** + * creates a subdirectory (and the parent directories if neccessary. + * + * @param path the name of the subdir to create + */ +void makeDirWithParents(ReByteBuffer& path, int minWidth){ + ReByteBuffer path2(path); + struct stat info; + do { + path2 = path; + int ix = path.indexOf(ReTraverser::m_separatorStr, minWidth); + path2.setLength(minWidth); + + } while(false); +} +/** + * Constructor. + */ +ReDirSync::ReDirSync() : + ReDirOptions(s_syncUsage, s_syncExamples) +{ + m_programArgs.addBool("mustexist", + i18n("files which don't exist on the target will not be copied"), + 'm', "must-exist", false); + addStandardFilterOptions(); +} + +/** + * Gets the arguments for the "list" command and execute this. + * + * @param argc the number of arguments + * @param argav the argument vector + */ +void ReDirSync::synchronize(int argc, char* argv[]){ + ReDirEntryFilter_t filter; + const char* sep = ReTraverser::m_separatorStr; + struct stat info; + try { + time_t start = time(NULL); + m_programArgs.init(argc, argv); + ReByteBuffer buffer; + if (m_programArgs.getArgCount() < 2) + help(i18n("missing argument(s) (source / target)")); + ReByteBuffer target(m_programArgs.getArg(m_programArgs.getArgCount() - 1)); + if (! target.endsWith(sep, 1)) + target.append(sep, 1); + if (stat(target.str(), &info) != 0) + help(i18n("target does not exist: $1"), target.str()); + else if (! S_ISDIR(info.st_mode)) + help(i18n("target is not a directory: $1"), target.str()); + size_t lengthTargetBase = target.length(); + bool verbose = ! m_programArgs.getBool("quiet"); + bool chatterMode = true; + setFilterFromProgramArgs(filter); + int64_t sumSizes = 0; + int files = 0; + int dirs = 0; + ReByteBuffer source; + ReByteBuffer targetFile; + int maxFileTimeDiff = 2; + for (int ix = 0; ix < m_programArgs.getArgCount() - 1; ix++){ + source.set(m_programArgs.getArg(ix), -1); + target.setLength(lengthTargetBase); + + if (stat(target.str(), &info) != 0) + help(i18n("source does not exist: $1"), source.str()); + else if (! S_ISDIR(info.st_mode)) + help(i18n("source is not a directory: $1"), source.str()); + if (! source.endsWith(sep, 1)){ + // the basename of the source will be appended to the target: + int startNode = source.rindexOf(sep, 1, 0, source.length() - 1); + target.append(source.str() + startNode, -1); + } + size_t ixSourceRelative = source.length(); + size_t ixTargetRelative = target.length(); + + ReTraverser traverser(source.str()); + traverser.setMinLevel(filter.m_maxDepth); + traverser.setMaxLevel(filter.m_maxDepth); + int level; + ReDirStatus_t* entry; + ReByteBuffer line; + while( (entry = traverser.nextFile(level, &filter)) != NULL){ + // 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) + makeDirWithParents(target, ixTargetRelative); + targetFile.set(target).append(entry->node(), -1); + bool exists = stat(targetFile.str(), &info) == 0; + if (! exists && ! copyExistingOnly + || entry->filetimeToTime(entry->modified()) - info.st_mtime + > maxFileTimeDiff) { + if (chatterMode) + printf("%s%s same time\n", entry->m_path.str(), entry->node); + continue; + } else { + + if (entry->isDirectory()) + dirs++; + else{ + files++; + sumSizes += entry->fileSize(); + } + if (verbose) + printf("%s\n", line.str()); + } + } + if (verbose){ + int duration = int(time(NULL) - start); +#if defined __linux__ + const char* prefix = "#"; +#elif defined __WIN32__ + const char* prefix = "rem"; +#endif + printf ("%s %d dir(s) and %d file(s) with %.6f MByte in %02d:%02d sec\n", + prefix, dirs, files, sumSizes / 1E6, duration / 60, duration % 60); + } + } catch(ReOptionException& exc){ + help(exc.getMessage()); + } +} /** * Gets the arguments for the "statistic" command and execute this. diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 301b000..7914afd 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -35,24 +35,32 @@ protected: int m_countCompoundUsage; }; -class ReDirList : public ReDirOptions { +class ReDirBatch : public ReDirOptions { public: - ReDirList(); + ReDirBatch(); public: - void list(int argc, char* argv[]); + void createBatch(int argc, char* argv[]); virtual bool printOneFile(ReDirStatus_t* entry) { return false; } }; -class ReDirBatch : public ReDirOptions { +class ReDirSync : public ReDirOptions { public: - ReDirBatch(); + ReDirSync(); public: - void createBatch(int argc, char* argv[]); + void synchronize(int argc, char* argv[]); +}; + +class ReDirList : public ReDirOptions { +public: + ReDirList(); +public: + void list(int argc, char* argv[]); virtual bool printOneFile(ReDirStatus_t* entry) { return false; } }; + class ReDirStatisticData{ public: ReDirStatisticData(); -- 2.39.5