#include "filesystem.hpp"
#include <cerrno>
+#include <cstdio>
+#include <cstring>
#ifdef _WIN32
+# include <conio.h>
# include <direct.h>
+# include <windows.h>
+#else
+# include <dirent.h>
+# include <sys/types.h>
#endif
#include <sys/stat.h>
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
+ std::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);
+}
+
+std::time_t file_mtime(const char *path) {
+ Stat info;
+ if (do_stat(path, info) != 0) {
+ return 0;
+ }
+ return get_mtime(info);
}
}
}
+
+bool remove_file(const std::string &path) {
+ return remove(path.c_str()) == 0;
+}
+
+
+bool remove_dir(const std::string &path) {
+#ifdef _WIN32
+
+ // shamelessly stolen from http://www.codeguru.com/forum/showthread.php?t=239271
+ const std::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 std::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 std::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
+}
+
}