"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
};
NULL
};
+const char* s_syncUsage[] = {
+ "<command>:",
+ "sy(nchronize) <opts> <source1> [<source2> ...] <target>",
+ " 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.
}
}
+/**
+ * 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.