1 #include "filesystem.hpp"
3 #include "../app/error.hpp"
17 # include <sys/types.h>
29 using Stat = struct _stat;
30 int do_stat(const char *path, Stat &info) {
31 return _stat(path, &info);
33 bool is_dir(const Stat &info) {
34 return (info.st_mode & _S_IFDIR) != 0;
36 bool is_file(const Stat &info) {
37 return (info.st_mode & _S_IFEG) != 0;
40 using Stat = struct stat;
41 int do_stat(const char *path, Stat &info) {
42 return stat(path, &info);
44 bool is_dir(const Stat &info) {
45 return S_ISDIR(info.st_mode);
47 bool is_file(const Stat &info) {
48 return S_ISREG(info.st_mode);
51 time_t get_mtime(const Stat &info) {
53 return info.st_mtimespec.tv_sec;
60 bool is_dir(const char *path) {
62 if (do_stat(path, info) != 0) {
68 bool is_file(const char *path) {
70 if (do_stat(path, info) != 0) {
76 time_t file_mtime(const char *path) {
78 if (do_stat(path, info) != 0) {
81 return get_mtime(info);
85 bool make_dir(const char *path) {
87 int ret = _mkdir(path);
89 int ret = mkdir(path, 0777);
95 bool make_dirs(const string &path) {
106 auto pos = path.find_last_of("\\/");
108 auto pos = path.find_last_of('/');
110 if (pos == string::npos) {
113 if (pos == path.length() - 1) {
114 // trailing separator, would make final make_dir fail
116 pos = path.find_last_of("\\/", pos - 1);
118 pos = path.find_last_of('/', pos - 1);
120 if (pos == string::npos) {
124 if (!make_dirs(path.substr(0, pos))) {
129 return make_dir(path);
132 // something's there, check if it's a dir and we're good
136 // whatever else went wrong, it can't be good
143 bool remove_file(const string &path) {
144 return remove(path.c_str()) == 0;
148 bool remove_dir(const string &path) {
151 // shamelessly stolen from http://www.codeguru.com/forum/showthread.php?t=239271
152 const string pattern = path + "\\*.*";
153 WIN32_FIND_DATA info;
154 HANDLE file = FindFirstFile(pattern.c_str(), &info);
155 if (file == INVALID_HANDLE_VALUE) {
156 // already non-existing
162 strncmp(info.cFileName, ".", 2) == 0 ||
163 strncmp(info.cFileName, "..", 3) == 0
167 const string sub_path = path + '\\' + info.cFileName;
168 if ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
169 if (!remove_dir(sub_path)) {
173 if (!SetFileAttributes(sub_path.c_str(), FILE_ATTRIBUTE_NORMAL)) {
176 if (!remove_file(sub_path)) {
180 } while (FindNextFile(file, &info));
183 DWORD error = GetLastError();
184 if (error != ERROR_NO_MORE_FILES) {
187 // is this (NORMAL vs DIRECTORY) really correct?
188 if (!SetFileAttributes(path.c_str(), FILE_ATTRIBUTE_NORMAL)) {
191 return RemoveDirectory(path.c_str());
195 DIR *dir = opendir(path.c_str());
196 for (dirent *entry = readdir(dir); entry != nullptr; entry = readdir(dir)) {
198 strncmp(entry->d_name, ".", 2) == 0 ||
199 strncmp(entry->d_name, "..", 3) == 0
203 const string sub_path = path + '/' + entry->d_name;
204 if (is_dir(sub_path)) {
205 if (!remove_dir(sub_path)) {
209 if (!remove_file(sub_path)) {
214 return remove(path.c_str()) == 0;
221 #if _DEFAULT_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE >= 200809L
222 char tmpl[] = "gong.XXXXXX";
223 const char *name = mkdtemp(tmpl);
225 throw app::SysError("unable to create temporary directory");
231 constexpr int max_tries = 10;
233 while (!make_dirs(name) && tries < max_tries) {
237 if (tries == max_tries) {
238 throw runtime_error("unable to create temporary directory");
244 TempDir::~TempDir() {
248 cerr << "warning: could not remove temp dir " << path << endl;