]> gitweb.hamatoma.de Git - crepublib/commitdiff
ReDirTool::synchronize()
authorhama <hama@siduction.net>
Sun, 25 Jan 2015 23:30:44 +0000 (00:30 +0100)
committerhama <hama@siduction.net>
Sun, 25 Jan 2015 23:30:44 +0000 (00:30 +0100)
cunit/cuReTraverser.cpp
os/ReDirTools.cpp
os/ReDirTools.hpp
os/ReTraverser.cpp
os/ReTraverser.hpp

index 9ba27750a2fb0a5574a0f036b732bd202e798bff..245105b12335d1e4fb5fcda65fda8bda32a65bd6 100644 (file)
@@ -22,16 +22,18 @@ public:
        }
 private:
     ReByteBuffer m_base;
+       ReByteBuffer m_buffer;
 private:
-    void makeDir(const char* relPath){
-        ReByteBuffer path(m_base);
-        path.append("/").append(relPath);
-        path.replaceAll("/", 1, OS_SEPARATOR, -1);
-        _mkdir(path.str());
+    const char* makeDir(const char* relPath){
+        m_buffer = m_base;
+        m_buffer.append(relPath);
+        m_buffer.replaceAll("/", 1, OS_SEPARATOR, -1);
+        _mkdir(m_buffer.str());
         struct stat info;
-        if (stat(path.str(), &info) != 0){
-            logF(true, "cannot create dir %1$s", path.str());
+        if (stat(m_buffer.str(), &info) != 0){
+            logF(true, "cannot create dir %1$s", m_buffer.str());
         }
+        return m_buffer.str();
     }
     void makeFile(const char* relPath){
         ReByteBuffer path(m_base);
@@ -59,6 +61,7 @@ private:
        void run(){
                initTree();
 
+               testToolSync();
                testToolStatistic();
                testBasic();
                testDirOptions();
@@ -80,7 +83,7 @@ private:
         trg.append("copy_x1.txt");
         ReByteBuffer buffer;
                buffer.ensureSize(5);
-        ReDirSync::copyFile(src.str(), 0, 0, -1ll, trg.str(), buffer,
+        ReDirSync::copyFile(src.str(), NULL, trg.str(), buffer,
                        ReLogger::globalLogger());
         checkFileEqu(src.str(), trg.str());
 #else
@@ -231,6 +234,15 @@ private:
                const char* argv[] = { "dt", "stat", "-P;*;-*/cache/*", m_base.str(), "2" };
                tools.main(5, (char**) argv);
        }
+       void testToolSync(){
+               ReDirTools tools;
+               ReByteBuffer source(m_base);
+               source.append("dir1");
+               ReByteBuffer target(makeDir("synctest"));
+               const char* argv[] = { "dt", "sync", "-P;*;-*/cache/*", "-p;*.txt",
+                       source.str(), target.str() };
+               tools.main(6, (char**) argv);
+       }
 };
 extern void testReTraverser(void);
 
index caef2c7598feeb301311cb793f5d43f9fb3bfb5d..5c3632fe560d173ca95d180115f59bf99aca8e14 100644 (file)
@@ -17,6 +17,11 @@ enum LOCATION_DIRTOOL {
        LC_COPY_FILE_4, // 50104
        LC_COPY_FILE_5, // 50105
        LC_COPY_FILE_6, // 50106
+       LC_MAKE_DIR_1,  // 50107
+       LC_MAKE_DIR_2,  // 50108
+       LC_SET_PROPERTIES_1,    // 50109
+       LC_SET_PROPERTIES_2,    // 50110
+       LC_SET_PROPERTIES_3,    // 50111
 };
 const char* ReDirTools::m_version = "2015.01.06";
 
@@ -1022,15 +1027,17 @@ void ReDirBatch::createBatch(int argc, const char* argv[]){
  *
  * @param path      the name of the subdir to create
  */
-void makeDirWithParents(ReByteBuffer& path, int minWidth){
-    ReByteBuffer path2(path);
+void ReDirSync::makeDirWithParents(const ReByteBuffer& path, int minWidth,
+                       ReTraverser& traverser){
     struct stat info;
-    do {
-        path2 = path;
-        int ix = path.indexOf(OS_SEPARATOR, minWidth);
-        path2.setLength(minWidth);
-        
-    } while(false);
+       if (stat(path.str(), &info) != 0){
+               ReFileProperties_t* props = NULL;
+#if defined __linux__
+               ReDirStatus_t* entry = traverser.topOfStack();
+               props = entry == NULL ? NULL : &entry->m_status;
+#endif
+               makeDirectory(path.str(), minWidth, props, ReLogger::globalLogger());
+       }
 }
 /**
  * Constructor.
@@ -1070,86 +1077,90 @@ ReDirSync::ReDirSync() :
  * @param target       the name of the target file
  */
 void ReDirSync::copyFile(ReDirStatus_t* entry, const char* target){
-       copyFile(entry->fullName(), entry->filetimeToTime(entry->modified()),
-               entry->filetimeToTime(entry->accessed()),
-               entry->fileSize(), target, m_buffer, ReLogger::globalLogger());
+       ReFileProperties_t* props;
+#ifdef __linux__
+       props = &entry->m_status;
+#else
+       ReFileProperties_t properties;
+       properties.m_modified = entry->modified();
+       properties.m_accessed = entry->accessed();
+       properties.m_size = entry->fileSize();
+       props = &properties;
+#endif
+       copyFile(entry->fullName(), props, target, m_buffer,
+               ReLogger::globalLogger());
 }
+
 /**
  * Copies a file.
  *
- * @param source       the source file name
- * @param modified     0 or modification time
- * @param accessed     0 or the access time
- * @param size         -1 or filesize
- * @param target       the name of the target file
- * @param buffer       OUT: the reading uses this buffer<br>
- *                                     Set the capacity to make it more efficient
- * @param logger       NULL or the logger for error messages
+ * @param source               the source file name
+ * @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>
+ *                                             Set the capacity to make it more efficient
+ * @param logger               NULL or the logger for error messages
+ * @return                             <code>true</code>success<br>
+ *                                             <code>false</code>error occurred
  */
-bool ReDirSync::copyFile(const char* source, time_t modified,
-               time_t accessed, int64_t size,
+bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties,
                const char* target, ReByteBuffer& buffer, ReLogger* logger){
        bool rc = false;
 #ifdef __linux__
-       if (size < 0ll || modified == 0){
-               struct stat info;
-               if (stat(source, &info) == 0){
-                       size = info.st_size;
-                       modified = info.st_mtime;
-                       accessed = info.st_atime;
+       struct stat info;
+       if (properties == NULL){
+               if (stat(source, &info) == 0)
+                       properties = &info;
+               else {
+                       if (logger != NULL)
+                               logger->sayF(LOG_ERROR, LC_COPY_FILE_1,
+                                       i18n("could not find: $ (errno: $2)")).arg(source)
+                                               .arg(errno).end();
                }
-               else if (logger != NULL)
-                       logger->sayF(LOG_ERROR, LC_COPY_FILE_1,
-                               i18n("could not find: $ (errno: $2)")).arg(source).arg(errno).end();
        }
-       if (size >= 0){
-               FILE* fpSource = fopen(source, "rb");
-               if (fpSource == NULL){
+       FILE* fpSource = fopen(source, "rb");
+       if (fpSource == NULL){
+               if (logger != NULL)
+                       logger->sayF(LOG_ERROR, LC_COPY_FILE_2,
+                                       i18n("cannot open $1 (errno: $2)"))
+                               .arg(source).arg(errno).end();
+       } else {
+               FileSize_t size = properties == NULL ? 0x7fffffff : properties->st_size;
+               FILE* fpTarget = fopen(target, "w");
+               if (fpTarget == NULL){
                        if (logger != NULL)
-                               logger->sayF(LOG_ERROR, LC_COPY_FILE_2,
+                               logger->sayF(LOG_ERROR, LC_COPY_FILE_3,
                                                i18n("cannot open $1 (errno: $2)"))
-                                       .arg(source).arg(errno).end();
-               } else {
-                       FILE* fpTarget = fopen(target, "w");
-                       if (fpTarget == NULL){
-                               if (logger != NULL)
-                                       logger->sayF(LOG_ERROR, LC_COPY_FILE_3,
-                                                       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, 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, LC_COPY_FILE_6,
-                                                                       i18n("cannot write $1 [$2] (errno: $3)"))
-                                                               .arg(target).arg(written).arg(errno).end();
-                                               break;
-                                       }
-                                       size -= blockSize;
+                                       .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, LC_COPY_FILE_5,
+                                                               i18n("cannot read $1 (errno: $2)"))
+                                                       .arg(source).arg(errno).end();
+                                       break;
                                }
-                               rc = size == 0ll;
-                               fclose(fpTarget);
-
-                               struct utimbuf times;
-
-                               times.actime = accessed;
-                               times.modtime = modified;
-                               utime(target, &times);
+                               size_t written;
+                               if ((written = fwrite(buffer.buffer(), 1, blockSize,
+                                               fpTarget)) != blockSize){
+                                       if (logger != NULL)
+                                               logger->sayF(LOG_ERROR, LC_COPY_FILE_6,
+                                                               i18n("cannot write $1 [$2] (errno: $3)"))
+                                                       .arg(target).arg(written).arg(errno).end();
+                                       break;
+                               }
+                               size -= blockSize;
                        }
-                       fclose(fpSource);
+                       rc = size == 0ll;
+                       fclose(fpTarget);
+                       if (properties != NULL)
+                               setProperties(target, properties, logger);
                }
+               fclose(fpSource);
        }
 #elif defined __WIN32__
     BOOL dummy;
@@ -1157,6 +1168,106 @@ bool ReDirSync::copyFile(const char* source, time_t modified,
 #endif
        return rc;
 }
+/**
+ * Sets the file properties.
+ *
+ * @param fullName             the name of the file
+ * @param properties   the properties like times and rights
+ * @param logger               NULL or the logger for error messages
+ * @return                             <code>true</code>: success<br>
+ *                                             <code>false</code>: error occurred
+ */
+bool ReDirSync::setProperties(const char* fullName,
+               ReFileProperties_t* properties, ReLogger* logger){
+       struct utimbuf times;
+       bool rc = true;
+       times.actime = properties->st_atime;
+       times.modtime = properties->st_mtime;
+       if (utime(fullName, &times) != 0){
+               if (logger != NULL)
+                       logger->sayF(LOG_ERROR, LC_SET_PROPERTIES_1,
+                               i18n("cannot change file times: $1 (errno: $2)"))
+                               .arg(fullName).arg(errno).end();
+               rc = false;
+       }
+       if (chmod(fullName, properties->st_mode) != 0) {
+               if (logger != NULL)
+                       logger->sayF(LOG_ERROR, LC_SET_PROPERTIES_2,
+                               i18n("cannot change file modes: $1 (errno: $2)"))
+                               .arg(fullName).arg(errno).end();
+               rc = false;
+       }
+       if (chown(fullName, properties->st_uid, properties->st_gid) != 0){
+               if (logger != NULL)
+                       logger->sayF(LOG_ERROR, LC_SET_PROPERTIES_3,
+                               i18n("cannot change file owner: $1 (errno: $2)"))
+                               .arg(fullName).arg(errno).end();
+               rc = false;
+       }
+       return rc;
+}
+
+/**
+ * Creates a directory and its parents (if neccessary).
+ *
+ * @param directory            the full name of the directory
+ * @param properties   NULL or the properties of the new directory
+ * @param logger               NULL or the logger for error messages
+ * @return                             <code>true</code>success<br>
+ *                                             <code>false</code>error occurred
+ */
+bool ReDirSync::makeDirectory(const char* directory, int minLength,
+               ReFileProperties_t* properties, ReLogger* logger){
+       bool rc = true;
+       ReByteBuffer path(directory);
+       int start = 0;
+#if defined __WIN32__
+       start = path.indexOf(":");
+#endif
+       int ixSlash = start;
+       struct stat info;
+       // for all parents and the full path itself:
+       while(ixSlash >= 0){
+               ixSlash = path.indexOf(OS_SEPARATOR_CHAR, ixSlash + 1);
+               // is the slash in front of the first node, e.g. 'e:\'?
+               if (ixSlash == start + 1)
+                       // not a real node: take the next node
+                       ixSlash = path.indexOf(OS_SEPARATOR_CHAR, ixSlash + 1);
+               if (ixSlash >= 0){
+                       // we handle only the next node:
+                       path.buffer()[ixSlash] = '\0';
+               }
+               // does the node exist?
+               if (lstat(path.str(), &info) != 0){
+                       // no, then we make it:
+                       if (mkdir(path.str(), 0) != 0){
+                               if (logger != NULL)
+                                       logger->sayF(LOG_ERROR, LC_MAKE_DIR_1,
+                                               i18n("could not make directory $1 (errno: $2)"))
+                                                       .arg(path.str()).arg(errno).end();
+                               rc = false;
+                               break;
+                       } else {
+#if defined __linux__
+                               if (properties != NULL){
+                                       //@ToDo: file time
+                                       if (chown(path.str(), properties->st_uid,
+                                               properties->st_gid) != 0 && logger != NULL)
+                                                       logger->sayF(LOG_ERROR, LC_MAKE_DIR_2,
+                                                               i18n("could not change owner/group of directory $1 (errno: $2)"))
+                                                                       .arg(path.str()).arg(errno).end();
+                               }
+#endif
+                       }
+               }
+               if (ixSlash >= 0){
+                       // restore the full path:
+                       path.buffer()[ixSlash] = OS_SEPARATOR_CHAR;
+               }
+       }
+       return rc;
+}
+
 /**
  * Gets the arguments for the "list" command and execute this.
  *
@@ -1221,7 +1332,7 @@ void ReDirSync::synchronize(int argc, const char* argv[]){
                                const char* targetRelativePath = target.str() + ixTargetRelative;
                 target.append(entry->m_path.str() + ixSourceRelative, -1);
                 if (stat(target.str(), &info) != 0)
-                    makeDirWithParents(target, ixTargetRelative);
+                    makeDirWithParents(target, ixTargetRelative, traverser);
                 targetFile.set(target).append(entry->node(), -1);
                 bool exists = stat(targetFile.str(), &info) == 0;
                 if (! exists && ! mustExist){
@@ -1359,6 +1470,8 @@ int ReDirTools::main(int argc, char* orgArgv[]){
         tools.help(argc, argv);
     else if (isArg("statistic", arg0))
         tools.statistic(argc, argv);
+    else if (isArg("synchronize", arg0))
+        tools.synchronize(argc, argv);
     else if (isArg("test", arg0)){
         void testAll();
         testAll();
@@ -1379,3 +1492,14 @@ void ReDirTools::statistic(int argc, const char* argv[]){
     statistic.run(argc, argv);
 }
 
+/**
+ * Gets the arguments for the "synchronize" command and execute this.
+ *
+ * @param argc      the number of arguments
+ * @param argav     the argument vector
+ */
+void ReDirTools::synchronize(int argc, const char* argv[]){
+    ReDirSync sync;
+    sync.synchronize(argc, argv);
+}
+
index 7d675f8e5f7942728d2635a22d33125a753857ee..a9ea3e9e0cfeb8679a958e9e39c04d2408d622a8 100644 (file)
@@ -50,6 +50,16 @@ protected:
        FILE* m_output;
 };
 
+#if defined __linux__
+typedef struct stat ReFileProperties_t;
+#else
+typedef struct {
+       FILETIME m_modified;
+       FILETIME m_accessed;
+       FileSize_t m_size;
+} ReFileProperties_t;
+#endif
+
 class ReDirBatch : public ReDirOptions {
 public:
     ReDirBatch();
@@ -66,10 +76,15 @@ public:
     void synchronize(int argc, const char* argv[]);
 protected:
        void copyFile(ReDirStatus_t* entry, const char* target);
-public:
-       static bool copyFile(const char* source, time_t modified, time_t accessed,
-               int64_t size, const char* target, ReByteBuffer& buffer,
-               ReLogger* logger = NULL);
+       void makeDirWithParents(const ReByteBuffer& path, int minWidth,
+                               ReTraverser& traverser);
+public:
+       static bool copyFile(const char* source, ReFileProperties_t* properties,
+               const char* target, ReByteBuffer& buffer, ReLogger* logger = NULL);
+       static bool makeDirectory(const char* directory, int minLength,
+               ReFileProperties_t* properties, ReLogger* logger = NULL);
+       static bool setProperties(const char* fullName,
+               ReFileProperties_t* properties, ReLogger* logger = NULL);
 protected:
        ReByteBuffer m_buffer;
 };
@@ -136,6 +151,7 @@ public:
     void list(int argc, const char* argv[]);
     void statisticUsage();
     void statistic(int argc, const char* argv[]);
+    void synchronize(int argc, const char* argv[]);
 public:
     static int main(int argc, char* argv[]);
 public:
index c88ebfd2678ddac8078a95ed34bd1da03ae2cfad..3a621419f95bd325725a7f489c3af6bc987336c4 100644 (file)
@@ -547,3 +547,18 @@ void ReTraverser::setPropertiesFromFilter(ReDirEntryFilter_t* filter){
        m_dirPatterns = filter->m_pathPatterns;\r
 }\r
 \r
+/**\r
+ * Returns the info of an entry the directory stack.\r
+ *\r
+ * @param offsetFromTop                0: return the top of stack<br>\r
+ *                                                     1: returns the entry one below the top<br>\r
+ *                                                     2: ...\r
+ * @return                                     NULL: not available<br>\r
+ *                                                     otherwise: the wanted entry\r
+ */\r
+ReDirStatus_t* ReTraverser::topOfStack(int offsetFromTop){\r
+       ReDirStatus_t* rc = NULL;\r
+       if (offsetFromTop >= 0 && m_level - offsetFromTop >= 0)\r
+               rc = m_dirs[m_level - offsetFromTop];\r
+       return rc;\r
+}\r
index 62e692d83c8ae5507a8b0396578870b0346b433f..0e0ce3d9da3929cb76cbc4770381151683887b8b 100644 (file)
@@ -123,6 +123,7 @@ public:
     void setMinLevel(int value)
     { m_minLevel = value; }
     void setPropertiesFromFilter(ReDirEntryFilter_t* filter);
+       ReDirStatus_t* topOfStack(int offset = 0);
 protected:
        bool initEntry(const ReByteBuffer& parent, const char* node, int level);
        void freeEntry(int level);