* @param path The path of the directory.
*/
ReDirectory::ReDirectory(const char* path) :
- 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_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);
*
* @param the status info given by <code>lstat()</code>
*/
-struct stat& ReDirectory::currentLStat(){
+struct stat& ReDirectory::currentLStat() {
#if defined linux
- if (m_stat.st_gid == (mode_t)-1 && filetimeIsUndefined(m_stat.st_mtim)){
+ if (m_stat.st_gid == (mode_t) -1 && filetimeIsUndefined(m_stat.st_mtim)) {
lstat(currentFull().str(), &m_stat);
}
#elif defined __WIN32__
- if (m_stat.st_mtime == (time_t) -1){
+ if (m_stat.st_mtime == (time_t) -1) {
stat(currentFull().str(), &m_stat);
}
#endif
*
* @return <code>true</code>: the current file is a directory
*/
-bool ReDirectory::currentIsDir(){
+bool ReDirectory::currentIsDir() {
#if defined __linux__
return S_ISDIR(currentLStat().st_mode);
#elif defined __WIN32__
}
/**
- * Returns whether the current file is a directory.
+ * Returns the modification date of the current entry.
*
- * @return <code>true</code>: the current file is a directory
+ * @return the modification date of the current entry
*/
-ReFileTime_t ReDirectory::currentModified(){
+ReFileTime_t ReDirectory::currentModified() {
#if defined __linux__
return currentLStat().st_mtim;
#elif defined __WIN32__
#endif
}
+/**
+ * Returns the size of the current entry.
+ *
+ * @return the filesize of the current entry
+ */
+int64_t ReDirectory::currentSize() {
+#if defined __linux__
+ return currentLStat().st_size;
+#elif defined __WIN32__
+ return m_data.ftLastWriteTime;
+#endif
+}
+
/**
* Deletes a directory tree.
*
* @param deleteBaseToo true: the directory itself will be deleted
* false: only the files and subdirs in the dir will be deleted
*/
-void ReDirectory::deleteTree(const char* base, bool deleteBaseToo) {
+void ReDirectory::deleteTree(const char* base, bool deleteBaseToo,
+ int* deletedDirs, int* deletedFiles, int64_t* deletedSize) {
if (true) {
ReDirectory dir(base);
if (dir.findFirst(ALL_FILES, false)) {
&& (node[1] == '\0' || (node[1] == '.' && node[2] == '\0'))))
&& stat(dir.currentFull().str(), &info) == 0) {
if (S_ISDIR(info.st_mode))
- deleteTree(dir.currentFull().str(), true);
- else
- _unlink(dir.currentFull().str());
+ deleteTree(dir.currentFull().str(), true, deletedDirs,
+ deletedFiles, deletedSize);
+ else if (unlink(dir.currentFull().str())
+ == 0&& deletedFiles != NULL)
+ ++*deletedFiles;
}
} while (dir.findNext());
}
dir.close();
- if (deleteBaseToo) {
- _rmdir(base);
- }
+ if (deleteBaseToo && _rmdir(base) && deletedDirs != NULL)
+ ++*deletedDirs;
}
}
* Returns the filetime of a given file.
*
* @param filename filename with path
- * @param modified OUT: the modification date. May be NULL
- * @param created OUT: the modification date. May be NULL
- * @param accessed OUT: the modification date. May be NULL
+ * @param modified OUT: the modification time. May be NULL
+ * @param created OUT: the file creation time. May be NULL
+ * @param accessed OUT: the last access time. May be NULL
*/
bool ReDirectory::filetime(const char* filename, ReFileTime_t* modified,
- ReFileTime_t* created, ReFileTime_t* accessed){
+ ReFileTime_t* created, ReFileTime_t* accessed) {
#if defined __linux__
struct stat info;
bool rc = stat(filename, &info) == 0;
- if (rc){
+ if (rc) {
if (modified != NULL)
- *m_modified = info.st_mtim;
+ *modified = info.st_mtim;
if (created != NULL)
*created = info.st_ctim;
- if (accessed != NULL
+ if (accessed != NULL)
*accessed = info.st_atim;
}
#elif defined __WIN32__
- HANDLE handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);\r
- bool rc = handle != INVALID_HANDLE_VALUE;\r
- if (rc){\r
- if (GetFileTime(handle, created, accessed, modified) == 0)\r
- rc = false;\r
- CloseHandle(handle);\r
+ HANDLE handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+ bool rc = handle != INVALID_HANDLE_VALUE;
+ if (rc) {
+ if (GetFileTime(handle, created, accessed, modified) == 0)
+ rc = false;
+ CloseHandle(handle);
}
#endif
return rc;
/** @brief Returns the filename of the current file with path.
* @return the full filename with path
*/
- const ReByteArray& currentFull(){
+ const ReByteArray& currentFull() {
if (m_currentFull.empty())
m_currentFull.set(m_path).append(currentNode());
return m_currentFull;
bool currentIsDir();
struct stat& currentLStat();
ReFileTime_t currentModified();
+ int64_t currentSize();
bool findFirst(const char* pattern, bool isRegExpr);
bool findNext();
bool findYoungest(ReByteArray& filename);
void setDir(const char* path);
void setRegExprFlags(int flags);
public:
- static void deleteTree(const char* base, bool deleteBaseToo = false);
+ static void deleteTree(const char* base, bool deleteBaseToo = false,
+ int* deletedDirs = NULL, int* deletedFiles = NULL,
+ int64_t* deletedSize = NULL);
static bool filetime(const char* filename, ReFileTime_t* modified,
- ReFileTime_t* created = NULL, ReFileTime_t* accessed = NULL);
+ ReFileTime_t* created = NULL, ReFileTime_t* accessed = NULL);
public:
static const char* ALL_FILES;
private:
* @param op2 second operand
* @return <code>true</code>: op1 == op2
*/
-inline bool operator ==(const ReFileTime_t& op1, const ReFileTime_t& op2){
+inline bool operator ==(const ReFileTime_t& op1, const ReFileTime_t& op2) {
#if defined __linux__
return op1.tv_sec == op2.tv_sec && op1.tv_nsec == op2.tv_nsec;
#else
return op1.dwHighDateTime == op2.dwHighDateTime
- && op1.dwLowDateTime == op2.dwLowDateTime;
+ && op1.dwLowDateTime == op2.dwLowDateTime;
#endif
}
/** Returns whether a filetime is equal than another.
* @param op2 second operand
* @return <code>true</code>: op1 == op2
*/
-inline bool operator !=(const ReFileTime_t& op1, const ReFileTime_t& op2){
- return ! (op1 == op2);
+inline bool operator !=(const ReFileTime_t& op1, const ReFileTime_t& op2) {
+ return !(op1 == op2);
}
/** Returns whether a filetime is greater (younger) than another.
* @param op1 first operand
* @param op2 second operand
* @return <code>true</code>: op1 > op2
*/
-inline bool operator >(const ReFileTime_t& op1, const ReFileTime_t& op2){
+inline bool operator >(const ReFileTime_t& op1, const ReFileTime_t& op2) {
#if defined __linux__
- return op1.tv_sec > op2.tv_sec || op1.tv_sec == op2.tv_sec && op1.tv_nsec > op2.tv_nsec;
+ return op1.tv_sec > op2.tv_sec
+ || op1.tv_sec == op2.tv_sec && op1.tv_nsec > op2.tv_nsec;
#else
return op1.dwHighDateTime > op2.dwHighDateTime
- || (op1.dwHighDateTime == op2.dwHighDateTime
- && op1.dwLowDateTime > op2.dwLowDateTime);
+ || (op1.dwHighDateTime == op2.dwHighDateTime
+ && op1.dwLowDateTime > op2.dwLowDateTime);
#endif
}
/** Returns whether a filetime is greater (younger) or equal than another.
* @param op2 second operand
* @return <code>true</code>: op1 > op2
*/
-inline bool operator >=(const ReFileTime_t& op1, const ReFileTime_t& op2){
+inline bool operator >=(const ReFileTime_t& op1, const ReFileTime_t& op2) {
#if defined __linux__
- return op1.tv_sec > op2.tv_sec || op1.tv_sec == op2.tv_sec && op1.tv_nsec >= op2.tv_nsec;
+ return op1.tv_sec > op2.tv_sec
+ || op1.tv_sec == op2.tv_sec && op1.tv_nsec >= op2.tv_nsec;
#else
return op1.dwHighDateTime > op2.dwHighDateTime
|| (op1.dwHighDateTime == op2.dwHighDateTime
* @param op2 second operand
* @return <code>true</code>: op1 > op2
*/
-inline bool operator <(const ReFileTime_t& op1, const ReFileTime_t& op2){
- return ! (op1 >= op2);
+inline bool operator <(const ReFileTime_t& op1, const ReFileTime_t& op2) {
+ return !(op1 >= op2);
}
/** Returns whether a filetime is lower (older) or equal than another.
* @param op1 first operand
* @param op2 second operand
* @return <code>true</code>: op1 > op2
*/
-inline bool operator <=(const ReFileTime_t& op1, const ReFileTime_t& op2){
+inline bool operator <=(const ReFileTime_t& op1, const ReFileTime_t& op2) {
return op1 == op2 || op1 < op2;
}
-
#endif /* REDIRECTORY_H_ */
ReByteArray ReTestUnit::m_tempDir;
+/**
+ * Stores the logging messages in a line sequence, inclusive the location as tag.
+ * This allows the retrieval whether a given error message is stored.
+ */
+class ReTestMemoryAppender: public ReMemoryAppender {
+public:
+ ReTestMemoryAppender() :
+ ReMemoryAppender(1000) {
+ // with 24 bit tag, 16-bit linecount
+ setSizes(3, 2);
+ }
+public:
+ bool contains(const char* message, bool ignoreCase = true);
+ bool containsLocation(int location);
+ virtual void say(ReLogger* logger, const char* message);
+};
+/**
+ * Tests whether the stored logging messages contains a given message.
+ *
+ * @param message message to search
+ * @param ignoreCase <code>true</code>: the search is case insensitive
+ * @return <code>true</code>: the message is stored<br>
+ * <code>false</code>: otherwise
+ */
+bool ReTestMemoryAppender::contains(const char* message, bool ignoreCase) {
+ ReByteArray line;
+ bool rc = false;
+ for (size_t ix = 0; !rc && ix < count(); ix++) {
+ get(ix, line);
+ rc = line.indexOf(message, -1, 0, -1, ignoreCase) >= 0;
+ }
+ return rc;
+}
+/**
+ * Tests whether the stored logging messages contains a given location.
+ *
+ * @param location location to search
+ * @return <code>true</code>: the location is stored<br>
+ * <code>false</code>: otherwise
+ */
+bool ReTestMemoryAppender::containsLocation(int location) {
+ ReByteArray line;
+ ReSeqArray::Tag tag;
+ bool rc = false;
+ for (size_t ix = 0; !rc && ix < count(); ix++) {
+ get(ix, line, &tag);
+ rc = tag == location;
+ }
+ return rc;
+}
+
+/**
+ * Stores a logging message.
+ *
+ * Distinction to ReMemoryAppender::say(): the location is stored as tag.
+ * This enables an easy retrieval.
+ *
+ * @param logger the caller
+ * @param message the logging message to store
+ */
+void ReTestMemoryAppender::say(ReLogger* logger, const char* message) {
+ int theCount = count();
+ if (theCount >= m_maxLines)
+ remove(theCount - 1);
+ // we store in reverse order:
+ add(0, message != NULL ? message : logger->asCString(), -1,
+ logger->currentLocation());
+}
+
/** @brief Constructor.
*
* @param name the name of the test class
m_name(name),
m_sourceFile(sourceFile),
m_buffer(),
- m_memoryAppender(new ReMemoryAppender(1024)),
+ m_memoryAppender(new ReTestMemoryAppender()),
m_silentLogger() {
m_silentLogger.addAppender(m_memoryAppender);
int ix = m_sourceFile.rindexOf(OS_SEPARATOR, 1);
}
}
+/**
+ * Checks whether the silent logger contains a given error message.
+ *
+ * @param location the location of the error message
+ * @param lineNo the line number of the test (for the error message)
+ */
+void ReTestUnit::assertLogContainsLocation(int location, int lineNo) {
+ bool rc = m_memoryAppender->containsLocation(location);
+ if (!rc) {
+ logF(true, "%s-%d: location not found: %d", m_sourceFile.str(), lineNo,
+ location);
+ ReByteArray logMsg;
+ logF(false, "log messages:\n%s--- end of log messages",
+ m_memoryAppender->join(logMsg).str());
+ }
+}
+
+/**
+ * Checks whether the silent logger contains a given part of an logging message.
+ *
+ * @param partOfMessage the string to search
+ * @param lineNo the line number of the test (for the error message)
+ */
+void ReTestUnit::assertLogContains(const char* partOfMessage, bool ignoreCase,
+ int lineNo) {
+ bool rc = m_memoryAppender->contains(partOfMessage, ignoreCase);
+ if (!rc) {
+ logF(true, "%s-%d: message not found: %s", m_sourceFile.str(), lineNo,
+ partOfMessage);
+ ReByteArray logMsg;
+ logF(false, "log messages:\n%s--- end of log messages",
+ m_memoryAppender->join(logMsg).str());
+ }
+}
+
/** @brief Checks a pointer expression. A not <code>null</code> value will be logged.
*
* @param pointer this expression will be tested
#ifndef RETESTUNIT_H_
#define RETESTUNIT_H_
-class ReMemoryAppender;
+class ReTestMemoryAppender;
class ReTestUnit {
public:
ReTestUnit(const char* name, const char* sourcefile);
void assertEqualFiles(const char* name1, const char* name2, int lineNo);
void assertFileExists(const char* name, int lineNo);
void assertFalse(bool conditon, int lineNo);
+ void assertLogContainsLocation(int location, int lineNo);
+ void assertLogContains(const char* partOfMessage, bool ignoreCase,
+ int lineNo);
void assertNotNull(void* pointer, int lineNo);
void assertNull(void* pointer, int lineNo);
void assertTrue(bool conditon, int lineNo);
ReByteArray m_name;
ReByteArray m_sourceFile;
ReByteArray m_buffer;
- ReMemoryAppender* m_memoryAppender;
+ ReTestMemoryAppender* m_memoryAppender;
ReLogger m_silentLogger;
protected:
static ReByteArray m_tempDir;
#define checkFileExists(fn) assertFileExists(fn, __LINE__)
#define checkDirExists(fn) assertDirExists(fn, __LINE__)
#define checkFileEqu(f1, f2) assertEqualFiles(f1, f2, __LINE__)
+#define checkLogContains(msg, ignoreCase) assertLogContains(msg, ignoreCase, __LINE__)
+#define checkLogContainsLocation(location) assertLogContainsLocation(location, __LINE__)
#endif /* RETESTUNIT_H_ */
ReDirDelete(m_logger).run(-1, argv2);
mayNotExist(s_allFiles);
}
+ void buildFile() {
+
+ }
+ void testSyncDelete() {
+ /*
+ rebuildTree();
+ ReByteArray srcDir(ReFileUtils::tempDir("src"));
+ ReByteArray trgDir(ReFileUtils::tempDir("trg"));
+ ReByteArray optOutput("--output-file=");
+ ReByteArray nameCurrent;
+ buildFilename("current", nameCurrent);
+ optOutput.append(nameCurrent);
+ const char* argv[] = { "sync", "--delete", optOutput.str(), m_base
+ .str(), NULL };
+ const char* existing[] = { //
+ " 1.txt", //
+ "*dir1", //
+ "*dir2", //
+ "*dir1/cache", //
+ "*dir1/dir1_1", //
+ "*dir1/dir1_2", //
+ "*dir1/dir1_2/dir1_2_1", //
+ " dir2/2.x", //
+ " dir1/cache/cache.txt", //
+ NULL };
+ const char* notExisting[] = { //
+ " dir1/dir1_2/dir1_2_1/x1.txt", //
+ " dir1/dir1_2/dir1_2_1/x2.txt", //
+ NULL };
+ ReDirDelete(m_logger).run(-1, argv);
+ mustExist(existing);
+ mayNotExist(notExisting);
+
+ const char* argv2[] = { "delete", optOutput.str(), m_base.str(), NULL };
+ ReDirDelete(m_logger).run(-1, argv2);
+ mayNotExist(s_allFiles);
+ */
+ }
void mustExist(const char** names) {
ReByteArray name;
struct stat info;
ReByteArray buffer;
buffer.ensureSize(5);
ReDirSync::copyFile(src.str(), false, NULL, trg.str(), buffer,
- ReLogger::globalLogger());
+ ReLogger::globalLogger());
checkFileEqu(src.str(), trg.str());
#else
log(false, "testCopyFile not implemented");
target.append("synctest", -1);
_mkdir(target.str(), ALLPERMS);
ReDirectory::deleteTree(target.str(), false);
- const char* argv[] = { "dt", "sync", "-P;*;-cache", "-p;*.txt", "-v3", optOutput.str(), source
- .str(), target.str() };
+ const char* argv[] = { "dt", "sync", "-P;*;-cache", "-p;*.txt", "-v3",
+ optOutput.str(), source.str(), target.str() };
tools.main(8, (char**) argv);
target.appendChar(OS_SEPARATOR_CHAR);
- for(const char** pFile = s_allFiles; *pFile != NULL; pFile++){
+ for (const char** pFile = s_allFiles; *pFile != NULL; pFile++) {
ReByteArray fullTarget(target);
fullTarget.append(*pFile);
- if (fullTarget.endsWith(".txt") || ! fullTarget.contains("cache")){
- checkT(stat(fullTarget.str(), &info) != 0);
+ if (fullTarget.endsWith(".txt") || !fullTarget.contains("cache")) {
+ checkT(stat(fullTarget.str(), &info) == 0);
} else {
- checkF(stat(fullTarget.str(), &info) != 0);
+ checkF(stat(fullTarget.str(), &info) == 0);
}
}
static const char* content =
"+dir1_2/dir1_2_1/x1.txt\n"
- "+dir1_2/dir1_2_1/x2.txt\n"
- "+cache/cache.txt\n"
- "-/tmp/retestunit/synctest/dir1/cache/cache.txt\n"
- "=== copied: * sec 3 file(s) 0.000074 MByte (* MB/sec).\n"
- "=== tree: 5 dir(s) 3 file(s) 0.000074 MByte";
+ "+dir1_2/dir1_2_1/x2.txt\n"
+ "+cache/cache.txt\n"
+ "-/tmp/retestunit/synctest/dir1/cache/cache.txt\n"
+ "=== copied: * sec 3 file(s) 0.000074 MByte (* MB/sec).\n"
+ "=== tree: 5 dir(s) 3 file(s) 0.000074 MByte\n"
+ "=== deleted: 1 dir(s) 1 file(s) 0.000020 MByte";
ReByteArray content2(content);
content2.replace('/', OS_SEPARATOR_CHAR);
testFileContentWithWildcards(nameCurrent, content2.str());
tools.main(6, (char**) argv);
}
/*
- " 1.txt", //
- "*dir1", //
- "*dir2", //
- "*dir1/cache", //
- "*dir1/dir1_1", //
- "*dir1/dir1_2", //
- "*dir1/dir1_2/dir1_2_1", //
- " dir1/dir1_2/dir1_2_1/x1.txt", //
- " dir1/dir1_2/dir1_2_1/x2.txt", //
- " dir2/2.x", //
- " dir1/cache/cache.txt", //
- NULL };
+ " 1.txt", //
+ "*dir1", //
+ "*dir2", //
+ "*dir1/cache", //
+ "*dir1/dir1_1", //
+ "*dir1/dir1_2", //
+ "*dir1/dir1_2/dir1_2_1", //
+ " dir1/dir1_2/dir1_2_1/x1.txt", //
+ " dir1/dir1_2/dir1_2_1/x2.txt", //
+ " dir2/2.x", //
+ " dir1/cache/cache.txt", //
+ NULL };
*/
};
* The latest sources: https://github.com/republib
*/
#include "base/rebase.hpp"
+#include "os/reos.hpp"
class TestReDirectory: public ReTestUnit {
public:
}
private:
void run() {
+ testDeleteTree();
testFileTime();
testBase();
}
+ void testDeleteTree() {
+ const char* base = "s4712";
+ const char* subDir = "s1";
+ ReByteArray dir(ReFileUtils::tempDir(base));
+ ReByteArray dir2(ReFileUtils::tempFile(subDir, base));
+ ReByteArray fn(dir2);
+ fn.appendChar(OS_SEPARATOR_CHAR).append("f1");
+ ReFileUtils::writeString(fn.str(), "xyz");
+ struct stat info;
+ checkEqu(0, stat(fn.str(), &info));
+ // delete exclusive base:
+ int files, dirs;
+ int64_t sizes;
+ ReDirectory::deleteTree(dir.str(), false, &dirs, &files, &sizes);
+ checkEqu(1, dirs);
+ checkEqu(1, files);
+ checkEqu(3L, sizes);
+ checkF(0 == stat(dir2.str(), &info));
+ // delete inclusive base:
+ _mkdir(dir2.str(), ALLPERMS);
+ checkEqu(0, stat(dir2.str(), &info));
+ ReFileUtils::writeString(fn.str(), "xyz0");
+ checkEqu(0, stat(fn.str(), &info));
+ ReDirectory::deleteTree(dir.str(), true, &dirs, &files, &sizes);
+ checkEqu(2, dirs);
+ checkEqu(1, files);
+ checkEqu(4L, sizes);
+ checkF(0 == stat(dir2.str(), &info));
+ }
void checkOrder(ReFileTime_t& time1, ReFileTime_t& time2,
ReFileTime_t& time3) {
checkT(time1 < time2);
}
private:
void run() {
+ testMakeDirectoryWithParents();
testReadWrite();
testSetFiles();
testTempFile();
ReFileUtils::writeString(fn.str(), "hi");
checkEqu(0, stat(fn.str(), &info));
}
+ void testMakeDirectoryWithParents() {
+ ReByteArray base(ReFileUtils::tempDir("s4711"));
+ ReByteArray dir(base);
+ dir.appendChar(OS_SEPARATOR_CHAR).append("d1").appendChar(
+ OS_SEPARATOR_CHAR).append("d2");
+ ReDirectory::deleteTree(base.str(), true);
+ struct stat info;
+ checkF(0 == stat(base.str(), &info));
+ // create 3 directories, not ending with a separator:
+ checkT(ReFileUtils::makeDirWithParents(dir.str()));
+ checkEqu(0, stat(dir.str(), &info));
+ checkEqu(0, _rmdir(dir.str()));
+ checkF(0 == stat(dir.str(), &info));
+ dir.appendChar(OS_SEPARATOR_CHAR);
+ // create the last directory, with an ending separator
+ checkT(ReFileUtils::makeDirWithParents(dir.str()));
+ checkEqu(0, stat(dir.str(), &info));
+
+ // Error: a node is a normal file
+ // Remove trailing separator
+ dir.setLength(dir.length() - 1);
+ checkEqu(0, _rmdir(dir.str()));
+ checkF(0 == stat(dir.str(), &info));
+ ReFileUtils::writeString(dir.str(), "x");
+ checkEqu(0, stat(dir.str(), &info));
+ checkF(S_ISDIR(info.st_mode));
+ checkF(
+ ReFileUtils::makeDirWithParents(dir.str(), &m_silentLogger));
+ checkLogContainsLocation(51003);
+ checkLogContains(dir.str(), false);
+ }
};
extern void testReFileUtils(void);
//
#include "base/rebase.hpp"
#include "os/reos.hpp"
-
+#if defined __WIN32__
int _tmain(int argc, _TCHAR* argv[]) {
ReDirTools tool;
tool.main(argc, argv);
return 0;
}
-
+#endif
#include "os/reos.hpp"
enum LOCATION_DIRTOOL {
- LC_SET_TIMES_1 = LOC_FIRST_OF(LOC_FILEUTILS), // 50101
+ LC_SET_TIMES_1 = LOC_FIRST_OF(LOC_FILEUTILS), // 51001
+ LC_MK_DIR_1, // 51002
+ LC_MK_DIR_2, // 51003
};
/**
#endif
}
+/**
+ * Creates a directory (if not it does not exist) and logs errors.
+ *
+ * @param path the full name
+ * @param logger NULL or the logger
+ * @return <code>true</code>: success: the directory exists<br>
+ * <code>false</code>: error occurred
+ */
+static bool ReFileUtils::makeDir(const char* path, ReLogger* logger) {
+ struct stat info;
+ bool rc = true;
+ if (stat(path, &info) != 0) {
+ rc = _mkdir(path, ALLPERMS) == 0;
+ if (!rc && logger != NULL)
+ logger->sayF(LOG_ERROR | CAT_FILE, LC_MK_DIR_1,
+ "can't create directory ($1): $2").arg(errno).arg(path).end();
+ } else if (!S_ISDIR(info.st_mode)) {
+ rc = false;
+ if (logger != NULL)
+ logger->sayF(LOG_ERROR | CAT_FILE, LC_MK_DIR_2,
+ "can't create directory (is a file): $1").arg(path).end();
+ }
+ return rc;
+}
+/**
+ * Creates a directory and (if necessary) its parent directories.
+ *
+ * @param path the full name
+ * @param logger NULL or the logger
+ * @return <code>true</code>: success: the directory exists<br>
+ * <code>false</code>: error occurred
+ */
+bool ReFileUtils::makeDirWithParents(const char* path, ReLogger* logger) {
+ const char* end;
+ const char* start = path;
+ bool rc = true;
+ ReByteArray dir;
+ while (rc && (end = strchr(start, OS_SEPARATOR_CHAR)) != NULL) {
+ if (end == path) {
+ start++;
+ dir.appendChar(OS_SEPARATOR_CHAR);
+ } else {
+ dir.append(start, end - start);
+ start = end + 1;
+ rc = makeDir(dir.str(), logger);
+ dir.appendChar(OS_SEPARATOR_CHAR);
+ }
+ }
+ if (rc && start[0] != '\0') {
+ dir.append(start);
+ rc = makeDir(dir.str(), logger);
+ }
+ return rc;
+}
/**
* Reads the content of a file into a buffer.
*
static ReByteArray& filetimeToString(const ReFileTime_t* time,
ReByteArray& buffer);
static time_t filetimeToTime(const ReFileTime_t* time);
+ static bool makeDir(const char* path, ReLogger* logger = NULL);
+ static bool makeDirWithParents(const char* path, ReLogger* logger =
+ NULL);
static ReByteArray& readString(const char* filename, ReByteArray& buffer);
static void setTimes(const char* name, ReFileTime_t modified,
ReFileTime_t* accessed = NULL, ReLogger* logger = NULL);