From: hama Date: Sun, 25 Jan 2015 23:30:44 +0000 (+0100) Subject: ReDirTool::synchronize() X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=4486c1e9cb69005a2d4855a055ae7924acda9e49;p=crepublib ReDirTool::synchronize() --- diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp index 9ba2775..245105b 100644 --- a/cunit/cuReTraverser.cpp +++ b/cunit/cuReTraverser.cpp @@ -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); diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index caef2c7..5c3632f 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -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
- * 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
+ * Set the capacity to make it more efficient + * @param logger NULL or the logger for error messages + * @return truesuccess
+ * falseerror 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, ×); + 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 true: success
+ * false: 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, ×) != 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 truesuccess
+ * falseerror 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); +} + diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 7d675f8..a9ea3e9 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -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: diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index c88ebfd..3a62141 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -547,3 +547,18 @@ void ReTraverser::setPropertiesFromFilter(ReDirEntryFilter_t* filter){ m_dirPatterns = filter->m_pathPatterns; } +/** + * Returns the info of an entry the directory stack. + * + * @param offsetFromTop 0: return the top of stack
+ * 1: returns the entry one below the top
+ * 2: ... + * @return NULL: not available
+ * otherwise: the wanted entry + */ +ReDirStatus_t* ReTraverser::topOfStack(int offsetFromTop){ + ReDirStatus_t* rc = NULL; + if (offsetFromTop >= 0 && m_level - offsetFromTop >= 0) + rc = m_dirs[m_level - offsetFromTop]; + return rc; +} diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp index 62e692d..0e0ce3d 100644 --- a/os/ReTraverser.hpp +++ b/os/ReTraverser.hpp @@ -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);