]> gitweb.hamatoma.de Git - crepublib/commitdiff
Tests in cuReFileUtils.cpp, dirtool
authorhama <hama@siduction.net>
Sat, 1 Aug 2015 23:04:58 +0000 (01:04 +0200)
committerhama <hama@siduction.net>
Sat, 1 Aug 2015 23:04:58 +0000 (01:04 +0200)
* copy file times + owner/rights

16 files changed:
base/ReDirectory.cpp
base/baselocations.hpp
base/rebase.hpp
cunit/cuReDirTools.cpp
cunit/cuReFileUtils.cpp [new file with mode: 0644]
cunit/cuReRandomizer.cpp
cunit/cuReTraverser.cpp
cunit/testall.cpp
math/ReRandomizer.cpp
net/ReTCP.cpp
os/ReDirTools.cpp
os/ReDirTools.hpp
os/ReFileUtils.cpp
os/ReFileUtils.hpp
os/ReTraverser.cpp
os/ReTraverser.hpp

index 5b666c99d437066965c7a12cf3d78697b856ee29..67912dfef78e83b576aaae81bb0d30e10b040663 100644 (file)
@@ -19,39 +19,42 @@ const char* ReDirectory::ALL_FILES = "";
 ReDirectory::ReDirectory() :
            m_path(),
            m_pattern(),
-           m_currentFull(),
            m_stat(),
+           m_currentFull(),
 #if defined __linux__
            m_dir(NULL),
            m_entry(NULL),
-// m_regExpr
+           m_regExpr(),
            m_regExprFlags(0),
            m_regExprIsInitialized(false),
            m_isRegExpr(false),
 #elif defined __WIN32__
            m_handle(INVALID_HANDLE_VALUE),
-//m_data()
+           m_data(),
 #endif
            m_valid(false) {
 }
+
 /** @brief Constructor.
  *
  * @param path         The path of the directory.
  */
 ReDirectory::ReDirectory(const char* path) :
-           m_path(),
-           m_pattern(),
-#if defined __linux__
-           m_dir(NULL),
-           m_entry(NULL),
-// m_regExpr
-           m_regExprFlags(0),
-           m_regExprIsInitialized(false),
-           m_isRegExpr(false),
-#elif defined __WIN32__
-           m_handle(0),
-//m_data(),
-#endif
+                   m_path(),
+                   m_pattern(),
+                   m_stat(),
+                   m_currentFull(),
+       #if defined __linux__
+                   m_dir(NULL),
+                   m_entry(NULL),
+                   m_regExpr(),
+                   m_regExprFlags(0),
+                   m_regExprIsInitialized(false),
+                   m_isRegExpr(false),
+       #elif defined __WIN32__
+                   m_handle(INVALID_HANDLE_VALUE),
+                   m_data(),
+       #endif
            m_valid(false) {
 #if defined __linux__
        memset(&m_regExpr, 0, sizeof m_regExpr);
@@ -103,7 +106,7 @@ const char* ReDirectory::currentNode() {
  * @param the status info given by <code>lstat()</code>
  */
 struct stat& ReDirectory::currentLStat(){
-       if (m_stat.st_gid == -1 && filetimeIsUndefined(m_stat.st_mtim)){
+       if (m_stat.st_gid == (mode_t)-1 && filetimeIsUndefined(m_stat.st_mtim)){
                lstat(currentFull().str(), &m_stat);
        }
        return m_stat;
index dca13615cbf1c59f4287f4f0320e83d5b76a5e89..10a27c4230270fd52826e35629186f5bd3cf8984 100644 (file)
@@ -26,6 +26,7 @@ enum ReModules_t {
        LOC_LOGGER,
        LOC_UDP,
        LOC_CSTRING,
+       LOC_FILEUTILS, /*510*/
 };
 #define LOC_FIRST_OF(moduleNo) (moduleNo*100+1)
 
index 8bc8c0789c3fc45efe370da3ce510dc73270a170..48f6ea3edad1dfc7bd6163e9196f0dc565af7a58 100644 (file)
@@ -89,6 +89,9 @@ inline void bzero(void* ptr, size_t size){
     memset(ptr, 0, size);
 }
 #endif
+// avoids warning like "parameter not used"
+#define reUseParam(var) (void) var
+
 enum ReOSType {
        OS_UNDEF,
        OS_LINUX = 'l',
@@ -129,7 +132,7 @@ inline int min(int a, int b) {
  * @return     maximum of a and b
  */
 inline int max(int a, int b) {
-       return a < b ? a : b;
+       return a > b ? a : b;
 }
 #include "base/ReClassId.hpp"
 #include "base/ReException.hpp"
index d373a7acab17a50a35135342743557d2183e9296..ddfadd608e01066abd061bff62ab62f22cecbba9 100644 (file)
@@ -219,8 +219,8 @@ private:
                trg.append("copy_x1.txt");
                ReByteArray buffer;
                buffer.ensureSize(5);
-               ReDirSync::copyFile(src.str(), NULL, trg.str(), buffer,
-                   ReLogger::globalLogger());
+               ReDirSync::copyFile(src.str(), false, NULL, trg.str(), buffer,
+                       ReLogger::globalLogger());
                checkFileEqu(src.str(), trg.str());
 #else
                log(false, "testCopyFile not implemented");
@@ -495,7 +495,7 @@ private:
                _mkdir(target.str(), ALLPERMS);
                const char* argv[] = { "dt", "sync", "--delete=1h", "-p;*.txt", source
                    .str(), target.str() };
-               //tools.main(6, (char**) argv);
+               tools.main(6, (char**) argv);
        }
        /*
            " 1.txt", //
diff --git a/cunit/cuReFileUtils.cpp b/cunit/cuReFileUtils.cpp
new file mode 100644 (file)
index 0000000..68f5092
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * cuReFileUtils.cpp
+ *
+ * License: Public Domain
+ * You can use and modify this file without any restriction.
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * You also can use the license from http://www.wtfpl.net/.
+ * The latest sources: https://github.com/republib
+ */
+
+#include "base/rebase.hpp"
+#include "os/reos.hpp"
+
+class TestReFileUtils: public ReTestUnit {
+public:
+       TestReFileUtils() :
+                   ReTestUnit("ReFileUtils", __FILE__) {
+               run();
+       }
+private:
+       void run() {
+               testReadWrite();
+               testSetFiles();
+               testTempFile();
+       }
+       void testReadWrite(){
+               ReByteArray name = ReFileUtils::tempFile("refiletest.$$$");
+               const char* content = "123\nabc\n";
+               ReFileUtils::writeString(name.str(), content);
+               ReByteArray buffer;
+               ReFileUtils::readString(name.str(), buffer);
+               checkEqu(content, buffer);
+
+               // invalid filename:
+               ReFileUtils::readString("/./././.", buffer);
+               checkEqu("", buffer);
+       }
+       void testSetFiles(){
+               ReByteArray name = ReFileUtils::tempFile("setfile_test.dat");
+               struct stat info;
+               unlink(name.str());
+               ReFileUtils::writeString(name.str(), "");
+               checkEqu(0, stat(name.str(), &info));
+               struct tm time1;
+               time1.tm_year = 2015 - 1900;
+               // March
+               time1.tm_mon = 2;
+               time1.tm_mday = 30;
+               time1.tm_hour = 11;
+               time1.tm_min = 33;
+               time1.tm_sec = 44;
+               time_t time2 = mktime(&time1);
+               ReFileTime_t time3;
+               ReFileUtils::timeToFiletime(time2, time3);
+               ReFileTime_t time4;
+               int diff = 86400 + 2 * 3600 + 3 * 60 + 2;
+               ReFileUtils::timeToFiletime(time2 +  diff, time4);
+               ReFileUtils::setTimes(name.str(), time3, &time4, NULL);
+               checkEqu(0, stat(name.str(), &info));
+               checkT(time2 == info.st_mtim.tv_sec);
+               checkT(time2 + diff == info.st_atim.tv_sec);
+       }
+       void testTempFile(){
+               const char* subdir = "refileutiltest";
+               const char* node = "test1.$$.txt";
+               ReByteArray dir = ReFileUtils::tempDir(subdir);
+               ReByteArray fn = ReFileUtils::tempFile(node, subdir);
+               checkT(fn.startsWith(dir.str()));
+               checkT(fn.endsWith(node));
+               unlink(fn.str());
+               struct stat info;
+               checkF(0 == stat(fn.str(), &info));
+               ReFileUtils::writeString(fn.str(), "hi");
+               checkEqu(0, stat(fn.str(), &info));
+       }
+};
+extern void testReFileUtils(void);
+
+void testReFileUtils(void) {
+       TestReFileUtils unit;
+}
+
+
+
+
index f099365a0204fcf97b3328a294119ae38e836c22..4da00f2082af74ff571b5c4c7e6e432922cd8d0a 100644 (file)
@@ -26,7 +26,7 @@ private:
        void testNextInt64Repeater() {
                ReCongruentialGenerator rand;
                const int MAX = 16;
-               time_t start = time(NULL);
+               clock_t start = clock();
                int64_t field[MAX];
                for (int ix = 0; ix < MAX; ix++)
                        field[ix] = rand.nextInt64();
@@ -36,11 +36,13 @@ private:
                        if (field[ix] != current)
                                checkEqu(field[ix], current);
                }
+               double duration = double(clock() - start) / CLOCKS_PER_SEC;
+               reUseParam(&duration);
        }
        void testNextInt64() {
                ReCongruentialGenerator rand;
                const int MAX = 16;
-               time_t start = time(NULL);
+               clock_t start = clock();
                int64_t field[MAX];
                for (int ix = 0; ix < MAX; ix++)
                        field[ix] = rand.nextInt64(ix + 10);
@@ -50,7 +52,8 @@ private:
                        if (!(field[ix] >= 0 && field[ix] <= ix + 10))
                                checkT(false);
                }
-               time_t diff = time(NULL) - start;
+               int diff = (int) (clock() - start);
+               reUseParam(&diff);
        }
 };
 extern void testReRandomizer(void);
index 379b751269090882dc0cb6d602b2825649773308..78c0c45010e2f88687155f8dfacd789537805032 100644 (file)
@@ -88,7 +88,7 @@ private:
                trg.append("copy_x1.txt");
                ReByteArray buffer;
                buffer.ensureSize(5);
-               ReDirSync::copyFile(src.str(), NULL, trg.str(), buffer,
+               ReDirSync::copyFile(src.str(), false, NULL, trg.str(), buffer,
                    ReLogger::globalLogger());
                checkFileEqu(src.str(), trg.str());
 #else
index 0b17811076b444f64956c75ce2c9e7a0fedad5df..b40077761d67901c1f30a04d7114ec18820d653f 100644 (file)
@@ -62,6 +62,8 @@ void testString() {
        testReMatcher();
 }
 void testOs() {
+       void testReFileUtils();
+       testReFileUtils();
        void testReDirTools();
        testReDirTools();
        void testReTraverser();
index 8500e340d4ad17035f2ee24e9da74cdd1d4ef1ca..62b0aabf32909d45599d13e0b0c800195ea4c0c8 100644 (file)
@@ -56,8 +56,6 @@ ReRandomizer::seed_t ReRandomizer::nearTrueRandom() {
 #if defined __linux__
        int fh = open("/dev/urandom", O_RDONLY);
        char buffer[sizeof(seed_t)];
-       size_t length = 0;
-
        if (read(fh, buffer, sizeof buffer) > 0)
                rc ^= *(seed_t*) buffer;
        close(fh);
@@ -131,7 +129,7 @@ int64_t ReRandomizer::nextInt64(int64_t maxValue, int64_t minValue) {
        }
        if (s_trace) {
                static int count = 0;
-               printf("%c %16llx ", count++ % 4 == 0 ? '\n' : ' ', rc);
+               printf("%c %16llx ", count++ % 4 == 0 ? '\n' : ' ', (long long) rc);
        }
        return rc;
 }
@@ -297,7 +295,7 @@ void ReCongruentialGenerator::setIncrement(seed_t increment) {
 void ReCongruentialGenerator::setSeed(seed_t seed) {
        m_seed = m_lastSetSeed = seed;
        if (s_trace)
-               printf(" Seed: %llx ", seed);
+               printf(" Seed: %llx ", (long long) seed);
 }
 
 /** @brief Returns the next 64 bit pseudo random number.
index 8abebb5938e38d1db5755599fdb36131a88173eb..1b1059c0a0297647cf1d7dd6d30119d471a1244e 100644 (file)
@@ -141,12 +141,16 @@ void ReSocketAddress::setAddress(const char* ip, int port) {
  *
  * @param logger       logger for the error handling
  */
+#ifdef __WIN32__
 #pragma warning( push )
 #pragma warning( disable : 4355 )
+#endif
 ReTCPClient::ReTCPClient(ReLogger* logger) :
            ReTCPConnection(-1, this),
            m_logger(logger) {
+#ifdef __WIN32__
 #pragma warning( pop )
+#endif
 }
 /**
  * Destructor.
@@ -392,13 +396,17 @@ void ReTCPConnection::send(const char* command, const char* data, int length) {
  * @param id           an identifier for logging
  * @param logger       the logger for error handling
  */
+#ifdef __WIN32__
 #pragma warning( push )
 #pragma warning( disable : 4355 )
+#endif
 ReTCPServerConnection::ReTCPServerConnection(int id, ReTCPServer* server) :
            ReTCPConnection(id, this),
            ReThread(true),
            m_server(server) {
+#ifdef __WIN32__
 #pragma warning( pop )
+#endif
 }
 
 /**
@@ -454,8 +462,10 @@ void ReTCPServerConnection::run() {
  * @param logger                       the logger for error handling
  * @param maxConnections       maximal count of threads handling a connection
  */
+#ifdef __WIN32__
 #pragma warning( push )
 #pragma warning( disable : 4355 )
+#endif
 ReTCPServer::ReTCPServer(int port, class ReNetCommandHandler& commandHandler,
     ReLogger* logger, int maxConnections) :
            ReTCPConnection(0, this),
@@ -463,7 +473,9 @@ ReTCPServer::ReTCPServer(int port, class ReNetCommandHandler& commandHandler,
            m_handler(commandHandler),
            m_logger(logger),
            m_threadPool(maxConnections, logger) {
+#ifdef __WIN32__
 #pragma warning( pop )
+#endif
        m_port = port;
 }
 
@@ -634,12 +646,16 @@ void ReNetCommandHandler::addHandler(ReNetCommandHandler* handler) {
  * @param port         port for listening
  * @param logger       logger for error handling
  */
+#ifdef __WIN32__
 #pragma warning( push )
 #pragma warning( disable : 4355 )
+#endif
 ReTCPEchoServer::ReTCPEchoServer(int port, ReLogger* logger) :
            ReTCPServer(port, *this, logger),
            ReNetCommandHandler() {
+#ifdef __WIN32__
 #pragma warning( pop )
+#endif
 }
 /**
  * Destructor.
@@ -669,7 +685,7 @@ ReNetCommandHandler::ProcessingState ReTCPEchoServer::handleNetCommand(
                connection->send("Strlen  ", m_toSend.str(), m_toSend.length());
                rc = PS_PROCESSED;
        } else if (command.equals("filldata")) {
-               int length = atol(data.str());
+               size_t length = (size_t) atol(data.str());
                if (m_toSend.length() != length || !m_toSend.startsWith("xxxxx"))
                        m_toSend.setLength(0).appendChar('x', length);
                connection->send("Filldata", m_toSend.str(), m_toSend.length());
index aef9a3b3df31420a8f2f63c67c0b1ba469ef3207..6757543f1eac9f978e485cf3f03209051c459ff8 100644 (file)
@@ -40,6 +40,9 @@ enum LOCATION_DIRTOOL {
        LC_DELETE_1,                            // 50123
        LC_DELETE_SUPERFLUOUS_1,        // 50124
        LC_SYNC_1,                                      // 50125
+       LC_COPY_FILE_7,                         // 50126
+       LC_ADAPT_PROPERTIES_1,          // 50127
+       LC_ADAPT_PROPERTIES_2,          // 50128
 };
 const char* ReDirTools::m_version = "2015.03.22";
 ReLogger* ReDirTools::m_logger = NULL;
@@ -401,7 +404,7 @@ ReFileTime_t ReDirOptions::checkDate(const char* value) {
                        rcTime += time(NULL);
        }
        ReFileTime_t rc;
-       ReDirStatus_t::timeToFiletime(rcTime, rc);
+       ReFileUtils::timeToFiletime(rcTime, rc);
        return rc;
 }
 /**
@@ -672,7 +675,7 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter& filter) {
                m_pathPatterns.set(buffer.str());
                filter.m_pathPatterns = &m_pathPatterns;
        }
-       if ((m_interval = m_programArgs.getInt("trace") * CLOCKS_PER_SEC) != 0){
+       if ((m_interval = m_programArgs.getInt("trace") * CLOCKS_PER_SEC) != 0) {
                m_triggerCount = 10;
        }
        if (m_programArgs.getString("output", buffer)[0] != '\0') {
@@ -686,8 +689,8 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter& filter) {
        int length;
        if (buffer.empty())
                m_verboseLevel = V_NORMAL;
-       else if ( (length = ReStringUtils::lengthOfUnsigned(buffer.str(),
-               buffer.length(), &nValue)) == 0 || length != buffer.length())
+       else if ((length = ReStringUtils::lengthOfUnsigned(buffer.str(),
+           buffer.length(), &nValue)) == 0 || length != (int) buffer.length())
                help("not a verbose level (0..5): ", buffer.str());
        else
                m_verboseLevel = VerboseLevel(min(V_DEBUG, nValue));
@@ -721,7 +724,6 @@ ReTool::ReTool(const char* usage[], const char* example[], int minArguments,
            m_traverser(NULL, this, logger),
            m_filter(),
            m_start(clock()),
-        //m_statInfo(),
            m_logger(logger) {
 #pragma warning( pop )
 }
@@ -770,7 +772,7 @@ void ReTool::run(int argc, const char** argv) {
                m_programArgs.init(argc, argv);
                if (m_programArgs.argCount() < m_minArguments)
                        m_programArgs.help(i18n("too few arguments"), false, stdout);
-               if (m_hasStandardArgs){
+               if (m_hasStandardArgs) {
                        checkStandardFilterOptions();
                        setFilterFromProgramArgs(m_filter);
                }
@@ -795,20 +797,23 @@ void ReTool::processFileArguments() {
        int max = m_programArgs.argCount() - m_reservedLast;
        // Test whether the arguments are files or directories:
        ReByteArray arg;
+       struct stat info;
        for (int ii = m_reservedFirst; ii < max; ii++) {
                arg = m_programArgs.arg(ii);
                if (!exists(arg) != 0)
                        m_programArgs.help(
-                           ReByteArray(i18n("not a file or a directory: ")).append(arg)
-                               .str(), false, stderr);
+                           ReByteArray(i18n("not a file or a directory: ")).append(arg).str(),
+                           false, stderr);
        }
        // process the files:
        for (int ii = m_reservedFirst; ii < max; ii++) {
-               const char* arg = m_programArgs.arg(ii);
-               if (S_ISDIR(m_statInfo.st_mode))
-                       processTree(arg);
-               else
-                       processSingleFile(arg);
+               ReByteArray arg(m_programArgs.arg(ii));
+               if (exists(arg, &info)) {
+                       if (S_ISDIR(info.st_mode))
+                               processTree(arg.str());
+                       else
+                               processSingleFile(arg.str());
+               }
        }
 }
 /**
@@ -900,8 +905,8 @@ void ReTool::printSummary(const char* prefix) {
                    duration == 0.0 ? 0.0 : (m_files + m_directories) / duration;
                line.append(rate, " %.1f").append(i18n("/sec"), -1);
                m_traverser.statisticAsString(line2);
-               line2.appendChar(' ').appendTime(int(duration * 1000)).append(" ", 1).append(
-                   i18n("sec"));
+               line2.appendChar(' ').appendTime(int(duration * 1000)).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,
@@ -1190,7 +1195,7 @@ void ReDirChecksum::buildStorage(const char* path, const char* storageFile) {
        if (fp == NULL) {
                m_logger->sayF(LOG_ERROR | CAT_FILE, LC_BUILD_DIRECTORY_1,
                    i18n("cannot open file: $1 (errno: $2)")).arg(storageFile).arg(
-               errno).end();
+                   errno).end();
 
        } else {
                int level;
@@ -1449,8 +1454,8 @@ ReDigest& ReDirChecksum::calculateChecksum(const char* name, ReDigest& digest,
        if (fp == NULL) {
                if (logger != NULL)
                        logger->sayF(LOG_ERROR | CAT_FILE, LC_CALCULATE_CHECKSUM_1,
-                           i18n("cannot open file: $1 (errno: $2)")).arg(name).arg(
-                       errno).end();
+                           i18n("cannot open file: $1 (errno: $2)")).arg(name).arg(errno)
+                           .end();
        } else {
                ReMD5 digest;
                size_t readBytes;
@@ -1911,11 +1916,11 @@ void ReDirTouch::processFile(ReDirStatus_t* entry) {
                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),
+                                   ReFileUtils::filetimeToString(&modified, bufferTime).str(),
+                                   ReFileUtils::filetimeToString(&accessed, bufferTime2).str(),
                                    name);
                        else {
-                               ReDirStatus_t::filetimeToString(
+                               ReFileUtils::filetimeToString(
                                    filetimeIsUndefined(m_modified) ? &accessed : &modified,
                                    bufferTime);
                                fprintf(m_output, "%s %s\n", bufferTime.str(), name);
@@ -1925,20 +1930,20 @@ void ReDirTouch::processFile(ReDirStatus_t* entry) {
                        ReByteArray 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),
+                                   ReFileUtils::filetimeToString(entry->modified(), bufferTime)
+                                       .str(),
+                                   ReFileUtils::filetimeToString(&modified, bufferTime2).str(),
+                                   ReFileUtils::filetimeToString(entry->accessed(),
+                                       bufferTime3).str(),
+                                   ReFileUtils::filetimeToString(&accessed, bufferTime4).str(),
                                    name);
                        else {
-                               ReDirStatus_t::filetimeToString(
+                               ReFileUtils::filetimeToString(
                                    filetimeIsUndefined(m_modified) ? &m_accessed : &m_modified,
                                    bufferTime);
                                fprintf(m_output, "%s -> %s %s\n",
-                                   ReDirStatus_t::filetimeToString(entry->modified(),
-                                       bufferTime2), bufferTime.str(), (char*) name);
+                                   ReFileUtils::filetimeToString(entry->modified(),
+                                       bufferTime2).str(), bufferTime.str(), (char*) name);
                        }
                }
        }
@@ -1977,7 +1982,7 @@ ReErrNo_t ReDirTouch::touch(const char* filename, const ReFileTime_t& modified,
        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();
+                   errno).end();
        return rc;
 }
 
@@ -2049,15 +2054,17 @@ ReDirSync::ReDirSync(ReLogger* logger) :
            i18n(
                "deletes the files/folders of the target directory not existing in the source directory.\n"
                        "If a time expression is given only files will be deleted if they are older than this.\n"
-                       "a time expression is a date, a time, a date/time or a relative time.\n"
-                       "relative times are a number and a unit.\n"
+                       "a time expression is a date, a time, a date/time or a relative time.\n"
+                       "relative times are a number and a unit.\n"
                        "units: m(inutes) h(hours), d(days). Default: m(inutes)\n"
                        "examples: -E7d --delete=30d -E24h -E2009.3.2/12:00 -E1999.01.01"),
            'E', "delete", true, NULL);
        m_programArgs.addBool("deletebefore",
-           i18n("deletes the superfluous files before copying.\n"
-               "This needs fewer space but it is more dangerous:\n"
-               "you have no time if the target is wrong: all files will be deleted"), 'B', "delete-before", false);
+           i18n(
+               "deletes the superfluous files before copying.\n"
+                       "This needs fewer space but it is more dangerous:\n"
+                       "you have no time if the target is wrong: all files will be deleted"),
+           'B', "delete-before", false);
        m_programArgs.addString("editor",
            i18n(
                "this editor will be started with a file containing a summary message (signals the end)"),
@@ -2079,13 +2086,17 @@ ReDirSync::ReDirSync(ReLogger* logger) :
 /**
  * Copies a file.
  *
- * @param entry                the source file info
- * @param target       the name of the target file
+ * @param dry                  logs the copy but do nothing (simulating mode)
+ * @param entry                        the source file info
+ * @param target               the name of the target file
+ * @param targetName   used for the logging
+ * @param trgProps     NULL or the properties of the (existing) target file
  */
-void ReDirSync::copyFile(ReDirStatus_t* entry, const char* target) {
+void ReDirSync::copyFile(bool dry, ReDirStatus_t* entry, const char* target,
+    const char* targetName, ReFileProperties_t* trgProps) {
        ReFileProperties_t* props;
 #ifdef __linux__
-       props = &entry->m_status;
+       props = entry->getStatus();
 #else
        ReFileProperties_t properties;
        properties.m_modified = *entry->modified();
@@ -2093,14 +2104,100 @@ void ReDirSync::copyFile(ReDirStatus_t* entry, const char* target) {
        properties.m_size = entry->fileSize();
        props = &properties;
 #endif
-       copyFile(entry->fullName(), props, target, m_buffer,
-           ReLogger::globalLogger());
+       if (dry
+           || copyFile(entry->fullName(), entry->isLink(), props, target, m_buffer,
+               ReLogger::globalLogger())) {
+               if (m_verboseLevel >= V_NORMAL) {
+                       if (entry->isLink())
+                               //@ or use targetRelativePath
+                               fprintf(m_output, "%c %s (symbolic link)%s\n",
+                                   trgProps != NULL ? '!' : '&', targetName,
+                                   dry ? " would be copied" : "");
+                       else
+                               fprintf(m_output, "%c%s%s\n", trgProps != NULL ? '!' : '+',
+                                   targetName, dry ? " would be copied" : "");
+               }
+               adaptProperties(entry->fullName(), props, target, NULL);
+       }
 }
 
+/**
+ * Tries to make the target properties are the same as the source properties.
+ *
+ * @param source       the name of the source file/directory
+ * @param srcProps     the source properties
+ * @param target       the name of the target file/directory
+ * @param trgProps     the target properties. If NULL the file is new
+ *                                     and all properties must be set
+ * @param verbose      verbose level: determines the output messages
+ * @param prefix       the first char of the output line
+ * @param output       NULL or the output stream, e.g. stdout
+ * @param logger       NULL or the logger for error messages
+ * @return                     <code>true</code>: success<br>
+ *                                     <code>false</code>: error occurred
+ */
+bool ReDirSync::adaptProperties(const char* source,
+    ReFileProperties_t* srcProps, const char* target,
+    ReFileProperties_t* trgProps, VerboseLevel verbose, char prefix,
+    FILE* output, ReLogger* logger) {
+       bool rc = true;
+#ifdef __linux__
+       ReByteArray changed;
+       if (trgProps == NULL || srcProps->st_uid != trgProps->st_uid
+           || srcProps->st_gid != trgProps->st_gid) {
+               if (chown(target, srcProps->st_uid, srcProps->st_gid) != 0) {
+                       rc = false;
+                       if (logger != NULL)
+                               logger->sayF(LOG_ERROR | CAT_FILE, LC_ADAPT_PROPERTIES_1,
+                                   i18n("could not change owner/group: $1 (errno: $2)")).arg(
+                                   target).arg(errno).end();
+               } else if (trgProps != NULL && verbose >= V_NORMAL) {
+                       if (verbose >= V_CHATTER) {
+                               if (srcProps->st_uid != trgProps->st_uid)
+                                       changed.append(" UID: ").appendInt(srcProps->st_uid).append(
+                                           "->").appendInt(trgProps->st_uid);
+                               if (srcProps->st_gid != trgProps->st_gid)
+                                       changed.append(" GID: ").appendInt(srcProps->st_gid).append(
+                                           "->").appendInt(trgProps->st_gid);
+                       } else {
+                               if (srcProps->st_uid != trgProps->st_uid)
+                                       changed.append(" UID");
+                               if (srcProps->st_gid != trgProps->st_gid)
+                                       changed.append(" GID");
+                       }
+               }
+       }
+       if (trgProps == NULL
+           || (srcProps->st_mode & ALLPERMS) != (trgProps->st_mode & ALLPERMS)) {
+               int mode = srcProps->st_mode & ALLPERMS;
+               if (chmod(target, mode) != 0 && logger != NULL) {
+                       rc = false;
+                       if (logger != NULL)
+                               logger->sayF(LOG_ERROR | CAT_FILE, LC_ADAPT_PROPERTIES_2,
+                                   i18n("could not change permissions: $1 (errno: $2)")).arg(
+                                   target).arg(errno).end();
+
+               } else if (verbose >= V_CHATTER) {
+                       changed.append(" rights: ").appendInt(
+                           (trgProps->st_mode & ALLPERMS), "%o").append("->").appendInt(
+                           mode);
+               } else if (verbose == V_NORMAL) {
+                       changed.append(" rights");
+               }
+       }
+       if (trgProps != NULL && verbose >= V_NORMAL && output != NULL) {
+               fprintf(output, "%c%s%s\n", prefix, source, changed.str());
+       }
+#else
+#error "not implemented"
+#endif
+       return rc;
+}
 /**
  * Copies a file.
  *
  * @param source               the source file name
+ * @param isLink               <code>true</code>: the source file is a symbolic link
  * @param properties   NULL or the properties of the source file
  * @param target               the name of the target file
  * @param buffer               OUT: the reading uses this buffer<br>
@@ -2109,8 +2206,9 @@ void ReDirSync::copyFile(ReDirStatus_t* entry, const char* target) {
  * @return                             <code>true</code>success<br>
  *                                             <code>false</code>error occurred
  */
-bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties,
-    const char* target, ReByteArray& buffer, ReLogger* logger) {
+bool ReDirSync::copyFile(const char* source, bool isLink,
+    ReFileProperties_t* properties, const char* target, ReByteArray& buffer,
+    ReLogger* logger) {
        bool rc = false;
 #ifdef __linux__
        struct stat info;
@@ -2121,52 +2219,72 @@ bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties,
                        if (logger != NULL)
                                logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_1,
                                    i18n("could not find: $1 (errno: $2)")).arg(source).arg(
-                               errno).end();
+                                   errno).end();
                }
        }
-       FILE* fpSource = fopen(source, "rb");
-       if (fpSource == NULL) {
-               if (logger != NULL)
-                       logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_2,
-                           i18n("cannot open $1 (errno: $2)")).arg(source).arg(errno).end();
-       } else {
-               ReFileSize_t size =
-                   properties == NULL ? 0x7fffffff : properties->st_size;
-               FILE* fpTarget = fopen(target, "w");
-               if (fpTarget == NULL) {
+       if (isLink) {
+               char reference[512];
+               int referenceLength = 0;
+               if ((referenceLength = readlink(source, reference, sizeof reference))
+                   < 0) {
                        if (logger != NULL)
+                               logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_2,
+                                   i18n("cannot read link $1 (errno: $2)")).arg(source).arg(
+                                   errno).end();
+               } else {
+                       reference[referenceLength] = '\0';
+                       unlink(target);
+                       if (symlink(reference, target) != 0 && logger != NULL)
                                logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_3,
-                                   i18n("cannot open $1 (errno: $2)")).arg(target).arg(errno)
+                                   i18n("cannot create link $1 [$2] (errno: $3)")).arg(target)
+                                   .arg(reference).arg(errno).end();
+               }
+       } else {
+               FILE* fpSource = fopen(source, "rb");
+               if (fpSource == NULL) {
+                       if (logger != NULL)
+                               logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_4,
+                                   i18n("cannot open $1 (errno: $2)")).arg(source).arg(errno)
                                    .end();
                } else {
-                       while (size > 0) {
-                               size_t blockSize = buffer.capacity();
-                               if ((int) blockSize > size)
-                                       blockSize = size;
-                               if (fread(buffer.buffer(), blockSize, 1, fpSource) != 1) {
-                                       if (logger != NULL)
-                                               logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_5,
-                                                   i18n("cannot read $1 (errno: $2)")).arg(source).arg(
-                                               errno).end();
-                                       break;
-                               }
-                               size_t written;
-                               if ((written = fwrite(buffer.buffer(), 1, blockSize, fpTarget))
-                                   != blockSize) {
-                                       if (logger != NULL)
-                                               logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_6,
-                                                   i18n("cannot write $1 [$2] (errno: $3)")).arg(
-                                                   target).arg(written).arg(errno).end();
-                                       break;
+                       ReFileSize_t size =
+                           properties == NULL ? 0x7fffffff : properties->st_size;
+                       FILE* fpTarget = fopen(target, "w");
+                       if (fpTarget == NULL) {
+                               if (logger != NULL)
+                                       logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_5,
+                                           i18n("cannot open $1 (errno: $2)")).arg(target).arg(
+                                           errno).end();
+                       } else {
+                               while (size > 0) {
+                                       size_t blockSize = buffer.capacity();
+                                       if ((int) blockSize > size)
+                                               blockSize = size;
+                                       if (fread(buffer.buffer(), blockSize, 1, fpSource) != 1) {
+                                               if (logger != NULL)
+                                                       logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_6,
+                                                           i18n("cannot read $1 (errno: $2)")).arg(source)
+                                                           .arg(errno).end();
+                                               break;
+                                       }
+                                       size_t written;
+                                       if ((written = fwrite(buffer.buffer(), 1, blockSize,
+                                           fpTarget)) != blockSize) {
+                                               if (logger != NULL)
+                                                       logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_7,
+                                                           i18n("cannot write $1 [$2] (errno: $3)")).arg(
+                                                           target).arg(written).arg(errno).end();
+                                               break;
+                                       }
+                                       size -= blockSize;
                                }
-                               size -= blockSize;
+                               rc = size == 0ll;
+                               fclose(fpTarget);
+                               if (properties != NULL)
+                                       setProperties(target, properties, logger);
                        }
-                       rc = size == 0ll;
-                       fclose(fpTarget);
-                       if (properties != NULL)
-                               setProperties(target, properties, logger);
+                       fclose(fpSource);
                }
-               fclose(fpSource);
        }
 #elif defined __WIN32__
        BOOL cancel = false;
@@ -2184,41 +2302,44 @@ bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties,
  * @param target               the target directory
  * @param deleteTime   UNDEF or a time: only files older than this will be deleted
  */
-void ReDirSync::deleteSuperfluous(const ReByteArray& source, const ReByteArray& target,
-               const ReFileTime_t& deleteTime){
+void ReDirSync::deleteSuperfluous(const ReByteArray& source,
+    const ReByteArray& target, const ReFileTime_t& deleteTime) {
        ReTraceUnit& tracer = *this;
        ReDirectory trg(target.str());
        if (trg.findFirst(ReDirectory::ALL_FILES, false)) {
                ReByteArray src, trg2;
                struct stat info;
-               ReFileTime_t modified;
                bool ignoreTime = filetimeIsUndefined(deleteTime);
                bool dry = m_programArgs.getBool("dry");
                do {
-                       if (strcmp(".", trg.currentNode()) == 0 || strcmp("..", trg.currentNode()) == 0)
+                       if (strcmp(".", trg.currentNode()) == 0
+                           || strcmp("..", trg.currentNode()) == 0)
                                continue;
                        if (tracer.isCountTriggered() && tracer.isTimeTriggered())
                                tracer.trace(trg.currentFull().str());
 
                        src.set(source).append(trg.currentNode());
-                       if (lstat(src.str(), &info) == 0){
-                               if (S_ISDIR(info.st_mode)){
+                       if (lstat(src.str(), &info) == 0) {
+                               if (S_ISDIR(info.st_mode)) {
                                        trg2.set(target).append(trg.currentNode());
                                        deleteSuperfluous(src, trg2, deleteTime);
                                }
-                       } else if (ignoreTime || trg.currentModified() >= deleteTime){
-                               if (trg.currentIsDir()){
-                                       if (! dry)
+                       } else if (ignoreTime || trg.currentModified() >= deleteTime) {
+                               if (trg.currentIsDir()) {
+                                       if (!dry)
                                                ReDirectory::deleteTree(trg.currentFull().str(), true);
                                        if (m_verboseLevel >= V_NORMAL)
-                                               fprintf(m_output, "-%s%s\n", trg.currentFull().str(), dry ? " would be deleted (dir)" : "");
+                                               fprintf(m_output, "-%s%s\n", trg.currentFull().str(),
+                                                   dry ? " would be deleted (dir)" : "");
                                } else {
                                        if (unlink(trg.currentFull().str()) != 0)
-                                               m_logger->sayF(LOG_ERROR | CAT_FILE, LC_DELETE_SUPERFLUOUS_1,
-                                                       i18n("cannot delete file: $1 (errno: $2)")).arg(trg.currentFull()).arg(
-                                                       errno).end();
+                                               m_logger->sayF(LOG_ERROR | CAT_FILE,
+                                                   LC_DELETE_SUPERFLUOUS_1,
+                                                   i18n("cannot delete file: $1 (errno: $2)")).arg(
+                                                   trg.currentFull()).arg(errno).end();
                                        else if (m_verboseLevel >= V_NORMAL)
-                                               fprintf(m_output, "-%s%s\n", trg.currentFull().str(), dry ? " would be deleted" : "");
+                                               fprintf(m_output, "-%s%s\n", trg.currentFull().str(),
+                                                   dry ? " would be deleted" : "");
                                }
                        }
                } while (trg.findNext());
@@ -2323,8 +2444,8 @@ bool ReDirSync::makeDirectory(const char* directory, int minLength,
        return rc;
 }
 
-static void printStatus(FILE* fp, double duration, int files, int sumSizes, int treeDirs,
-       int treeFiles, int64_t treeSumSizes){
+static void printStatus(FILE* fp, double duration, int files, int sumSizes,
+    int treeDirs, int treeFiles, int64_t treeSumSizes) {
        fprintf(fp,
            i18n(
                "=== copied:    %02d:%02d sec  %7d file(s) %12.6f MByte (%.3f MB/sec).\n"
@@ -2342,9 +2463,10 @@ void ReDirSync::doIt() {
        ReByteArray buffer;
        ReByteArray target(m_programArgs.arg(m_programArgs.argCount() - 1));
        target.removeLastChar(OS_SEPARATOR_CHAR);
-       if (!exists(target))
+       struct stat info;
+       if (!exists(target, &info))
                help(i18n("target does not exist: "), target.str());
-       else if (!S_ISDIR(m_statInfo.st_mode))
+       else if (!S_ISDIR(info.st_mode))
                help(i18n("target is not a directory: $1"), target.str());
        size_t lengthTargetBase = target.length();
        bool addOnly = m_programArgs.getBool("add");
@@ -2356,9 +2478,9 @@ void ReDirSync::doIt() {
        ReFileTime_t deleteDate;
        setFiletimeUndef(deleteDate);
        bool deleteBefore = m_programArgs.getBool("deletebefore");
-       if (m_programArgs.getString("delete", buffer) != NULL){
+       if (m_programArgs.getString("delete", buffer) != NULL) {
                deleteTarget = true;
-               if (! buffer.empty())
+               if (!buffer.empty())
                        deleteDate = checkDate(buffer.str());
        }
 
@@ -2376,7 +2498,7 @@ void ReDirSync::doIt() {
                        source.reduceLength();
                if (!exists(source))
                        help(i18n("source does not exist: $1"), source.str());
-               else if (!S_ISDIR(m_statInfo.st_mode))
+               else if (!S_ISDIR(info.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:
@@ -2394,18 +2516,19 @@ void ReDirSync::doIt() {
                int level;
                ReDirStatus_t* entry;
                ReByteArray line;
+               struct stat targetInfo;
                while ((entry = m_traverser.nextFile(level, &filter)) != NULL) {
                        if (entry->isDirectory())
                                continue;
                        // append the new relative path from source to target:
                        target.setLength(ixTargetRelative);
                        target.append(entry->m_path.str() + ixSourceRelative, -1);
-                       if (!exists(target) && ! dry)
+                       if (!exists(target) && !dry)
                                makeDirWithParents(target, ixTargetRelative, m_traverser);
                        targetFile.set(target).append(entry->node(), -1);
                        const char* targetRelativePath = targetFile.str() + ixTargetRelative
                            + 1;
-                       bool targetExists = exists(targetFile);
+                       bool targetExists = exists(targetFile, &targetInfo);
                        if (!targetExists && mustExist) {
                                if (m_verboseLevel == V_CHATTER)
                                        fprintf(m_output, "-ignored: %s does not exist\n",
@@ -2419,7 +2542,7 @@ void ReDirSync::doIt() {
                                                    targetRelativePath);
                                        continue;
                                }
-                               if (ignoreDate && entry->fileSize() == m_statInfo.st_size) {
+                               if (ignoreDate && entry->fileSize() == targetInfo.st_size) {
                                        if (m_verboseLevel >= V_CHATTER)
                                                fprintf(m_output, "_ignored: %s same size\n",
                                                    targetRelativePath);
@@ -2427,8 +2550,8 @@ void ReDirSync::doIt() {
                                }
                                // target younger than source?
                                int diff = int(
-                                   m_statInfo.st_mtime
-                                       - entry->filetimeToTime(entry->modified()));
+                                   targetInfo.st_mtime
+                                       - ReFileUtils::filetimeToTime(entry->modified()));
                                if (!ignoreDate && (diff <= maxFileTimeDiff || diff == 3600)) {
                                        if (m_verboseLevel >= V_CHATTER)
                                                fprintf(m_output, "=ignored: %s same time\n",
@@ -2438,13 +2561,10 @@ void ReDirSync::doIt() {
                        }
                        files++;
                        sumSizes += entry->fileSize();
-                       if (m_verboseLevel >= V_NORMAL)
-                               fprintf(m_output, "%c%s%s\n", targetExists ? '!' : '+',
-                                   targetRelativePath, dry ? " would be copied" : "");
-                       if (!dry)
-                               copyFile(entry, targetFile.str());
+                       copyFile(dry, entry, targetFile.str(), targetRelativePath,
+                           &targetInfo);
                }
-               if (deleteTarget && ! deleteBefore)
+               if (deleteTarget && !deleteBefore)
                        deleteSuperfluous(source, target, deleteDate);
                treeFiles += m_traverser.files();
                treeDirs += m_traverser.directories();
@@ -2452,20 +2572,21 @@ void ReDirSync::doIt() {
        }
        double duration = double((clock() - m_start)) / CLOCKS_PER_SEC;
        if (m_verboseLevel >= V_SUMMARY) {
-               printStatus(m_output, duration, files, sumSizes, treeDirs,
-                               treeFiles, treeSumSizes);
+               printStatus(m_output, duration, files, sumSizes, treeDirs, treeFiles,
+                   treeSumSizes);
        }
-       if (m_programArgs.getString("editor", buffer) != NULL){
+       if (m_programArgs.getString("editor", buffer) != NULL) {
                ReByteArray tempFile = ReFileUtils::tempDir("redirtool.status.");
                tempFile.appendInt(time(NULL), "%x").append(".txt");
                FILE* fp = fopen(tempFile.str(), "w");
                if (fp == NULL)
                        m_logger->sayF(LOG_ERROR | CAT_FILE, LC_SYNC_1,
-                               i18n("cannot open status file ($1): $2")).arg(errno).arg(tempFile).end();
+                           i18n("cannot open status file ($1): $2")).arg(errno).arg(
+                           tempFile).end();
                else {
                        fprintf(fp, i18n("backup finished!\n\n"));
-                       printStatus(fp, duration, files, sumSizes, treeDirs,
-                               treeFiles, treeSumSizes);
+                       printStatus(fp, duration, files, sumSizes, treeDirs, treeFiles,
+                           treeSumSizes);
                        fclose(fp);
                        buffer.insert(0, "\"", -1);
                        buffer.append("\" ").append(tempFile);
@@ -2541,7 +2662,7 @@ void ReDirTCP::runOneThreadClient(const char* ip, int port, int rounds,
     int interval, int bufferSize, bool upload) {
        ReTCPClient client(m_logger);
        if (client.connect(ip, port)) {
-               time_t start = time(NULL);
+               clock_t start = clock();
                const char* command = upload ? "strlen" : "filldata";
                ReByteArray message;
                if (upload)
@@ -2550,7 +2671,7 @@ void ReDirTCP::runOneThreadClient(const char* ip, int port, int rounds,
                        message.appendInt(bufferSize);
                time_t lastPrint = start;
                int64_t size = 0;
-               int duration = 0;
+               double duration = 0;
                ReByteArray answer, data;
                client.setLogSendReceive(false);
                int64_t sizeCurrent = 0;
@@ -2571,10 +2692,10 @@ void ReDirTCP::runOneThreadClient(const char* ip, int port, int rounds,
                                sizeCurrent = 0;
                        }
                }
-               duration = int(time(NULL) - start);
-               if (duration == 0)
-                       duration = 1;
-               printf("%2d: %9.3f MiByte %8.3f kiByte %s/sec %s\n", rounds,
+               duration = int(clock() - start) / CLOCKS_PER_SEC;
+               if (duration == 0.0)
+                       duration = 0.001;
+               printf("%2d: %9.3f MiByte %8.3f kiByte/sec %s\n", rounds,
                    size / 1024.0 / 1024, (double) size / duration / 1024,
                    upload ? "up" : "down");
 
index a792ec67d832ba3d2adcd73c71c0c8fe53801e61..f50b21891f0882081bf6d745566875d5996651b8 100644 (file)
@@ -102,21 +102,25 @@ protected:
        virtual void processTree(const char* filename);
        /** Tests whether a file or directory exists:
         @param name    can be changed and recovered!
+        @param props   NULL or the properties of the file
         @return                <code>true</code>: a file with the given name exists
         */
-       inline bool exists(ReByteArray& name) {
+       inline bool exists(ReByteArray& name, struct stat* props = NULL) {
+               struct stat info;
+               if (props == NULL)
+                       props = &info;
 #if defined __linux__
                // linux ignores a trailing slash:
-               return stat(name.str(), &m_statInfo) == 0;
+               return stat(name.str(), props) == 0;
 #elif defined __WIN32__
                int ix = name.length() - 1;
                if (ix >= 0 && name.str()[ix] != OS_SEPARATOR_CHAR)
-                   ix = -1;
+               ix = -1;
                else
-                   name.setLength(ix);
-               bool rc = stat(name.str(), &m_statInfo) == 0;
+               name.setLength(ix);
+               bool rc = stat(name.str(), props) == 0;
                if (ix >= 0)
-                   name.appendChar(OS_SEPARATOR_CHAR);
+               name.appendChar(OS_SEPARATOR_CHAR);
                return rc;
 #endif
        }
@@ -129,7 +133,6 @@ protected:
        ReTraverser m_traverser;
        ReDirEntryFilter m_filter;
        clock_t m_start;
-       struct stat m_statInfo;
        ReLogger* m_logger;
 };
 
@@ -269,14 +272,20 @@ public:
        ReDirSync(ReLogger* logger);
 protected:
        virtual void doIt();
-       void copyFile(ReDirStatus_t* entry, const char* target);
+       void copyFile(bool dry, ReDirStatus_t* entry, const char* target,
+           const char* targetRelative, ReFileProperties_t* trgProps);
        void deleteSuperfluous(const ReByteArray& source, const ReByteArray& target,
-               const ReFileTime_t& deleteTime);
+           const ReFileTime_t& deleteTime);
        void makeDirWithParents(ReByteArray& path, int minWidth,
            ReTraverser& traverser);
 public:
-       static bool copyFile(const char* source, ReFileProperties_t* properties,
-           const char* target, ReByteArray& buffer, ReLogger* logger = NULL);
+       static bool adaptProperties(const char* source,
+           ReFileProperties_t* srcProps, const char* target, struct stat* trgProps,
+           VerboseLevel verbose = V_QUIET, char prefix = ':', FILE* output = NULL,
+           ReLogger* logger = NULL);
+       static bool copyFile(const char* source, bool isLink,
+           ReFileProperties_t* properties, const char* target, ReByteArray& buffer,
+           ReLogger* logger = NULL);
        static bool makeDirectory(const char* directory, int minLength,
            ReFileProperties_t* properties, ReLogger* logger = NULL);
        static bool setProperties(const char* fullName,
index 97c979b84ee8c48a4f49ddceaa4403e2b85c724b..737d37c840b65c49bd17ae29287c884af6881b6b 100644 (file)
  * You also can use this license: http://www.wtfpl.net
  * The latest sources: https://github.com/republib
  */
-#include "base/rebase.hpp"\r
-#include "os/reos.hpp"\r
-\r
-/**\r
- * Returns the name of a subdirectory in the temporary directory.\r
- *\r
- * If the directory does not exist it will be created.\r
- *\r
- * @param node  the name of the subdirectory\r
- * @return      the full name of the subdirectory\r
- */\r
-ReByteArray ReFileUtils::tempDir(const char* node){\r
-    ReByteArray rc;\r
-       if (getenv("TMP") != NULL) {\r
-               rc = getenv("TMP");\r
-       } else if (getenv("TEMP")) {\r
-               rc = getenv("TEMP");\r
-       } else {\r
-#if defined __linux__\r
-               rc = "/tmp/";\r
-#elif defined __WIN32__\r
-        rc = "c:\\temp";\r
-#endif\r
-       }\r
-    if (node != NULL){\r
-        rc.ensureLastChar(OS_SEPARATOR_CHAR);\r
-        rc.append(node);\r
-        _mkdir(rc.str(), ALLPERMS);\r
-    }\r
-    return rc;\r
-}\r
-/**\r
- * Returns the name of a file in a subdirectory in the temporary directory.\r
- *\r
- * If the directory does not exist it will be created.\r
- *\r
- * @param node  the name of the subdirectory\r
- * @param node  the name of the subdirectory\r
- * @param       the full name of the subdirectory\r
- */\r
-ReByteArray ReFileUtils::tempFile(const char* node, const char* subdir){\r
-    ReByteArray rc = tempDir(subdir);\r
-    rc.ensureLastChar(OS_SEPARATOR_CHAR);\r
-    rc.append(node);\r
-    return rc;\r
-}\r
+#include "base/rebase.hpp"
+#include "os/reos.hpp"
+
+enum LOCATION_DIRTOOL {
+       LC_SET_TIMES_1 = LOC_FIRST_OF(LOC_FILEUTILS), // 50101
+};
+
+/**
+ * Converts a filetime to a string.
+ *
+ * @param time         the filetime to convert
+ * @param buffer       OUT: the buffer for the string
+ * @return                     <code>buffer.str()</code>, e.g. "2014.01.07 02:59:43"
+ */
+ReByteArray& ReFileUtils::filetimeToString(const ReFileTime_t* time,
+    ReByteArray& 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;
+}
+
+/**
+ * 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 ReFileUtils::filetimeToTime(const ReFileTime_t* filetime) {
+#ifdef __linux__
+       return filetime->tv_sec;
+#elif defined __WIN32__
+       // 64-bit arithmetic:
+       LARGE_INTEGER date, adjust;
+       date.HighPart = filetime->dwHighDateTime;
+       date.LowPart = filetime->dwLowDateTime;
+       // 100-nanoseconds = milliseconds * 10000
+       adjust.QuadPart = 11644473600000 * 10000;
+       // removes the diff between 1970 and 1601
+       date.QuadPart -= adjust.QuadPart;
+       // converts back from 100-nanoseconds to seconds
+       time_t rc = (time_t) (date.QuadPart / 10000000);
+#if defined __WIN32__
+       static int s_diffTime = 0x7fffffff;
+       if (s_diffTime == 0x7fffffff) {
+               s_diffTime = 0;
+               ReByteArray tempFile = ReFileUtils::tempFile("$$redir$$.tmp", NULL);
+               const char* filename = tempFile.str();
+               FILE* fp = fopen(filename, "w");
+               if (fp != NULL) {
+                       struct stat info;
+                       int rcStat = stat(filename, &info);
+                       fclose(fp);
+                       if (rcStat == 0) {
+                               WIN32_FIND_DATAA data;
+                               HANDLE handle = FindFirstFile(filename, &data);
+                               if (handle != INVALID_HANDLE_VALUE) {
+                                       time_t other = filetimeToTime(&data.ftLastWriteTime);
+                                       s_diffTime = info.st_mtime - other;
+                                       FindClose(handle);
+                               }
+                       }
+               }
+       }
+       rc += s_diffTime;
+#endif
+       return rc;
+#endif
+}
+
+/**
+ * Reads the content of a file into a buffer.
+ *
+ * @param filename     name of the file to read
+ * @param buffer       OUT: the buffer for the content
+ * @return                     <code>buffer</code> (for chaining)
+ */
+ReByteArray& ReFileUtils::readString(const char* filename,
+    ReByteArray& buffer) {
+       struct stat info;
+       buffer.setLength(0);
+       if (stat(filename, &info) == 0 && !S_ISDIR(info.st_mode)) {
+               FILE* fp = fopen(filename, "rb");
+               if (fp != NULL) {
+                       int length = info.st_size;
+                       buffer.setLength(length);
+                       int readBytes;
+                       readBytes = fread((void*) buffer.buffer(), 1, length, fp);
+                       buffer.setLength(max(readBytes, 0));
+                       fclose(fp);
+               }
+       }
+       return buffer;
+}
+/**
+ * Sets the file time/times.
+ *
+ * @param name         the filename
+ * @param modified     the time of modification
+ * @param accessed     NULL or the time of the last access
+ */
+void ReFileUtils::setTimes(const char* name, ReFileTime_t modified,
+    ReFileTime_t* accessed, ReLogger* logger) {
+#if defined linux
+       struct timeval vals[2];
+       if (accessed == NULL) {
+               vals[0].tv_sec = time(NULL);
+               vals[0].tv_usec = 0;
+       } else {
+               vals[0].tv_sec = accessed->tv_sec;
+               vals[0].tv_usec = accessed->tv_nsec / 1000;
+       }
+       vals[1].tv_sec = modified.tv_sec;
+       vals[1].tv_usec = modified.tv_nsec / 1000;
+       if (utimes(name, vals) == 0 && logger != NULL)
+               logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_TIMES_1,
+                   "cannot change times ($1): $2").arg(errno).arg(name).end();
+
+#elif defined __WIN32__
+#error "not implemented"
+#endif
+}
+
+/**
+ * Returns the name of a subdirectory in the temporary directory.
+ *
+ * If the directory does not exist it will be created.
+ *
+ * @param node  NULL or the name of the subdirectory. If NULL the OS specific
+ *                             temporary directory will returned
+ * @return      the full name of the subdirectory
+ */
+ReByteArray ReFileUtils::tempDir(const char* node) {
+       ReByteArray rc;
+       if (getenv("TMP") != NULL) {
+               rc = getenv("TMP");
+       } else if (getenv("TEMP")) {
+               rc = getenv("TEMP");
+       } else {
+#if defined __linux__
+               rc = "/tmp/";
+#elif defined __WIN32__
+               rc = "c:\\temp";
+#endif
+       }
+       if (node != NULL) {
+               rc.ensureLastChar(OS_SEPARATOR_CHAR);
+               rc.append(node);
+               _mkdir(rc.str(), ALLPERMS);
+       }
+       return rc;
+}
+/**
+ * Returns the name of a file in a subdirectory in the temporary directory.
+ *
+ * If the directory does not exist it will be created.
+ *
+ * @param node  the name of the subdirectory
+ * @param node  the name of the subdirectory
+ * @param       the full name of the subdirectory
+ */
+ReByteArray ReFileUtils::tempFile(const char* node, const char* subdir) {
+       ReByteArray rc = tempDir(subdir);
+       rc.ensureLastChar(OS_SEPARATOR_CHAR);
+       rc.append(node);
+       return rc;
+}
+/**
+ * Converts the unix time (time_t) to the file time.
+ *
+ * @param time                 the unix time (secondes since 1.1.1970)
+ * @param filetime     OUT: the OS specific filetime
+ */
+void ReFileUtils::timeToFiletime(time_t time, ReFileTime_t& filetime) {
+#ifdef __linux__
+       filetime.tv_sec = time;
+       filetime.tv_nsec = 0;
+#elif defined __WIN32__
+       LONGLONG ll = Int32x32To64(time, 10000000) + 116444736000000000;
+       filetime.dwLowDateTime = (DWORD)ll;
+       filetime.dwHighDateTime = ll >> 32;
+#endif
+}
+
+/**
+ * Writes a string into a file.
+ *
+ * @param filename     the name of the file to write
+ * @param content      the string to write
+ */
+void ReFileUtils::writeString(const char* filename, const char* content) {
+       FILE* fp = fopen(filename, "w");
+       if (fp != NULL) {
+               int length = strlen(content);
+               int written = fwrite(content, 1, length, fp);
+               reUseParam(written);
+               fclose(fp);
+       }
+}
index f4b8e1b9e806f00ad57f137f1228f7a1f5811326..8ac5a44ab5f5b7497fff06d48c2a5813f0634879 100644 (file)
@@ -8,12 +8,20 @@
  * You also can use this license: http://www.wtfpl.net
  * The latest sources: https://github.com/republib
  */
-#if ! defined REFILE_UTILS_HPP\r
-#define REFILE_UTILS_HPP\r
-\r
-class ReFileUtils {\r
-public:\r
-    static ReByteArray tempDir(const char* node);\r
-    static ReByteArray tempFile(const char* node, const char* subdir);\r
-};\r
-#endif
\ No newline at end of file
+#if ! defined REFILE_UTILS_HPP
+#define REFILE_UTILS_HPP
+
+class ReFileUtils {
+public:
+       static ReByteArray& filetimeToString(const ReFileTime_t* time,
+           ReByteArray& buffer);
+       static time_t filetimeToTime(const ReFileTime_t* time);
+       static ReByteArray& readString(const char* filename, ReByteArray& buffer);
+       static void setTimes(const char* name, ReFileTime_t modified,
+           ReFileTime_t* accessed = NULL, ReLogger* logger = NULL);
+       static ReByteArray tempDir(const char* node = NULL);
+       static ReByteArray tempFile(const char* node, const char* subdir = NULL);
+       static void timeToFiletime(time_t time, ReFileTime_t& filetime);
+       static void writeString(const char* filename, const char* content);
+};
+#endif
index d09ad8309bd1a783166a8b591eb85a189fc58725..971d5659b87db333e2c4246734996f18de0f6dfa 100644 (file)
@@ -88,72 +88,9 @@ ReFileSize_t ReDirStatus_t::fileSize() {
  * @return          <code>buffer.str()</code> (for chaining)
  */
 const char* ReDirStatus_t::filetimeAsString(ReByteArray& buffer) {
-       return filetimeToString(modified(), buffer);
+       return ReFileUtils::filetimeToString(modified(), buffer).str();
 }
 
-/**
- * Converts a filetime to a string.
- *
- * @param time         the filetime to convert
- * @param buffer       OUT: the buffer for the string
- * @return                     <code>buffer.str()</code>, e.g. "2014.01.07 02:59:43"
- */
-const char* ReDirStatus_t::filetimeToString(const ReFileTime_t* time,
-    ReByteArray& 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->tv_sec;
-#elif defined __WIN32__
-       // 64-bit arithmetic:
-       LARGE_INTEGER date, adjust;
-       date.HighPart = filetime->dwHighDateTime;
-       date.LowPart = filetime->dwLowDateTime;
-       // 100-nanoseconds = milliseconds * 10000
-       adjust.QuadPart = 11644473600000 * 10000;
-       // removes the diff between 1970 and 1601
-       date.QuadPart -= adjust.QuadPart;
-       // converts back from 100-nanoseconds to seconds
-       time_t rc = (time_t) (date.QuadPart / 10000000);
-#if defined __WIN32__
-    static int s_diffTime = 0x7fffffff;
-    if (s_diffTime == 0x7fffffff){
-        s_diffTime = 0;
-        ReByteArray tempFile = ReFileUtils::tempFile("$$redir$$.tmp", NULL);
-        const char* filename = tempFile.str();
-        FILE* fp = fopen(filename, "w");
-        if (fp != NULL){
-            struct stat info;
-            int rcStat = stat(filename, &info);
-            fclose(fp);
-            if (rcStat == 0) {
-                   WIN32_FIND_DATAA data;
-                HANDLE handle = FindFirstFile(filename, &data);
-                if (handle != INVALID_HANDLE_VALUE){
-                    time_t other = filetimeToTime(&data.ftLastWriteTime);
-                    s_diffTime = info.st_mtime - other; 
-                    FindClose(handle);
-                }
-            }
-        }
-    }
-    rc += s_diffTime;
-#endif
-       return rc;
-#endif
-}
 
 /**
  * Loads the info about the first file into the instance.
@@ -495,22 +432,6 @@ const char* ReDirStatus_t::rightsAsString(ReByteArray& buffer, bool numerical,
        return buffer.str();
 }
 
-/**
- * Converts the unix time (time_t) to the file time.
- *
- * @param time                 the unix time (secondes since 1.1.1970)
- * @param filetime     OUT: the OS specific filetime
- */
-void ReDirStatus_t::timeToFiletime(time_t time, ReFileTime_t& filetime) {
-#ifdef __linux__
-       filetime.tv_sec = time;
-       filetime.tv_nsec = 0;
-#elif defined __WIN32__
-       LONGLONG ll = Int32x32To64(time, 10000000) + 116444736000000000;
-       filetime.dwLowDateTime = (DWORD)ll;
-       filetime.dwHighDateTime = ll >> 32;
-#endif
-}
 /**
  * Returns the type of the entry.
  * return       the file type, e.g. TF_REGULAR
index 865f2fd1ce391397d13d93f04d9896587aa1a87c..5c934bb970f2910328c18dcdf62cc49dd321d2a0 100644 (file)
@@ -61,15 +61,11 @@ public:
        Type_t type();
        char typeAsChar();
 public:
-       static const char* filetimeToString(const ReFileTime_t* time,
-           ReByteArray& buffer);
-       static time_t filetimeToTime(const ReFileTime_t* time);
 #if defined __WIN32__
        static bool getFileOwner(HANDLE handle, const char* file, ReByteArray& name,
                ReLogger* logger = NULL);
        static bool getPrivilege(const char* privilege, ReLogger* logger);
 #endif
-       static void timeToFiletime(time_t time, ReFileTime_t& filetime);
 public:
        ReByteArray m_path;
        ReByteArray m_fullName;