X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fio%2Ffilesystem.cpp;h=5a4515e78dfab5629e5ce806b0622d9822829cc2;hb=ce10bfbe252d5598bbb559c6ce55aed1b9393227;hp=8a06d1c9ef8b64051c5596d687f8e5fd833e5423;hpb=ede25c0a2f59e21521d1cd962e6ea9d78169ca12;p=blank.git diff --git a/src/io/filesystem.cpp b/src/io/filesystem.cpp index 8a06d1c..5a4515e 100644 --- a/src/io/filesystem.cpp +++ b/src/io/filesystem.cpp @@ -1,44 +1,81 @@ #include "filesystem.hpp" #include +#include +#include +#include +#include +#include #ifdef _WIN32 +# include # include +# include +#else +# include +# include #endif #include +using namespace std; + namespace blank { -bool is_dir(const char *path) { +namespace { #ifdef _WIN32 - struct _stat info; - if (_stat(path, &info) != 0) { - return false; + using Stat = struct _stat; + int do_stat(const char *path, Stat &info) { + return _stat(path, &info); + } + bool is_dir(const Stat &info) { + return (info.st_mode & _S_IFDIR) != 0; + } + bool is_file(const Stat &info) { + return (info.st_mode & _S_IFEG) != 0; } - return (info.st_mode & _S_IFDIR) != 0; #else - struct stat info; - if (stat(path, &info) != 0) { - return false; + using Stat = struct stat; + int do_stat(const char *path, Stat &info) { + return stat(path, &info); + } + bool is_dir(const Stat &info) { + return S_ISDIR(info.st_mode); } - return S_ISDIR(info.st_mode); + bool is_file(const Stat &info) { + return S_ISREG(info.st_mode); + } +#endif + time_t get_mtime(const Stat &info) { +#ifdef __APPLE__ + return info.st_mtimespec.tv_sec; +#else + return info.st_mtime; #endif + } } -bool is_file(const char *path) { -#ifdef _WIN32 - struct _stat info; - if (_stat(path, &info) != 0) { +bool is_dir(const char *path) { + Stat info; + if (do_stat(path, info) != 0) { return false; } - return (info.st_mode & _S_IFREG) != 0; -#else - struct stat info; - if (stat(path, &info) != 0) { + return is_dir(info); +} + +bool is_file(const char *path) { + Stat info; + if (do_stat(path, info) != 0) { return false; } - return S_ISREG(info.st_mode); -#endif + return is_file(info); +} + +time_t file_mtime(const char *path) { + Stat info; + if (do_stat(path, info) != 0) { + return 0; + } + return get_mtime(info); } @@ -52,7 +89,7 @@ bool make_dir(const char *path) { } -bool make_dirs(const std::string &path) { +bool make_dirs(const string &path) { if (make_dir(path)) { return true; } @@ -67,7 +104,7 @@ bool make_dirs(const std::string &path) { #else auto pos = path.find_last_of('/'); #endif - if (pos == std::string::npos) { + if (pos == string::npos) { return false; } if (pos == path.length() - 1) { @@ -77,7 +114,7 @@ bool make_dirs(const std::string &path) { #else pos = path.find_last_of('/', pos - 1); #endif - if (pos == std::string::npos) { + if (pos == string::npos) { return false; } } @@ -99,4 +136,114 @@ bool make_dirs(const std::string &path) { } } + +bool remove_file(const string &path) { + return remove(path.c_str()) == 0; +} + + +bool remove_dir(const string &path) { +#ifdef _WIN32 + + // shamelessly stolen from http://www.codeguru.com/forum/showthread.php?t=239271 + const string pattern = path + "\\*.*"; + WIN32_FIND_DATA info; + HANDLE file = FindFirstFile(pattern.c_str(), &info); + if (file == INVALID_HANDLE_VALUE) { + // already non-existing + return true; + } + + do { + if ( + strncmp(info.cFileName, ".", 2) == 0 || + strncmp(info.cFileName, "..", 3) == 0 + ) { + continue; + } + const string sub_path = path + '\\' + info.cFileName; + if ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { + if (!remove_dir(sub_path)) { + return false; + } + } else { + if (!SetFileAttributes(sub_path.c_str(), FILE_ATTRIBUTE_NORMAL)) { + return false; + } + if (!remove_file(sub_path)) { + return false; + } + } + } while (FindNextFile(file, &info)); + FindClose(file); + + DWORD error = GetLastError(); + if (error != ERROR_NO_MORE_FILES) { + return false; + } + // is this (NORMAL vs DIRECTORY) really correct? + if (!SetFileAttributes(path.c_str(), FILE_ATTRIBUTE_NORMAL)) { + return false; + } + return RemoveDirectory(path.c_str()); + +#else + + DIR *dir = opendir(path.c_str()); + for (dirent *entry = readdir(dir); entry != nullptr; entry = readdir(dir)) { + if ( + strncmp(entry->d_name, ".", 2) == 0 || + strncmp(entry->d_name, "..", 3) == 0 + ) { + continue; + } + const string sub_path = path + '/' + entry->d_name; + if (is_dir(sub_path)) { + if (!remove_dir(sub_path)) { + return false; + } + } else { + if (!remove_file(sub_path)) { + return false; + } + } + } + return remove(path.c_str()) == 0; + +#endif +} + + +TempDir::TempDir() { +#if _DEFAULT_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE >= 200809L + char tmpl[] = "blank.XXXXXX"; + const char *name = mkdtemp(tmpl); + if (!name) { + throw runtime_error("unable to create temporary directory"); + } + path = name; +#else + char name[L_tmpnam]; + tmpnam(name); + constexpr int max_tries = 10; + int tries = 0; + while (!make_dirs(name) && tries < max_tries) { + tmpnam(name); + ++tries; + } + if (tries == max_tries) { + throw runtime_error("unable to create temporary directory"); + } +#endif + path = name; +} + +TempDir::~TempDir() { + try { + remove_dir(path); + } catch (...) { + cerr << "warning: could not remove temp dir " << path << endl; + } +} + }