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";
*
* @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.
* @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, ×);
+ 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;
#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, ×) != 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.
*
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){
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();
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);
+}
+