24# include <sys/types.h>
29# include <sys/types.h>
34# include <mach-o/dyld.h>
57 if (::_stat(pathname, &statbuf) < 0)
61 if (::stat(pathname, &statbuf) < 0)
75 if (::_stat(pathname, &statbuf) < 0)
78 if (!(statbuf.st_mode & _S_IFDIR))
82 if (::stat(pathname, &statbuf) < 0)
85 if (!S_ISDIR(statbuf.st_mode))
99 if (::_stat(pathname, &statbuf) < 0)
102 if (!(statbuf.st_mode & _S_IFREG))
106 if (::stat(pathname, &statbuf) < 0)
109 if (!S_ISREG(statbuf.st_mode))
122 return ::_getcwd(buf, size);
124 return ::getcwd(buf, size);
134 return ::_chdir(pathname) >= 0;
136 return ::chdir(pathname) >= 0;
146 if (::_mkdir(pathname) < 0)
149 if (::mkdir(pathname, S_IRWXU | S_IRGRP | S_IXGRP) < 0)
162 return ::_rmdir(pathname) >= 0;
164 return ::rmdir(pathname) >= 0;
173 return ::_unlink(pathname) >= 0;
175 return ::unlink(pathname) >= 0;
193 if (!SUCCEEDED(::SHGetFolderPathA(0, CSIDL_APPDATA, 0, 0,
app_data_path)))
220 if (!SUCCEEDED(::SHGetFolderPathA(0, CSIDL_APPDATA, 0, 0,
home_path)))
223 uid_t user_id = ::geteuid();
224 struct passwd* user_info = ::getpwuid(user_id);
225 if (user_info ==
nullptr || user_info->pw_dir ==
nullptr)
239 if (std::rename(from, to) < 0)
250 std::ifstream src_stream(src, std::ios::binary);
251 if (!src_stream.good())
253 std::ofstream dst_stream(dst, std::ios::binary);
254 if (!dst_stream.good())
257 int const BUFFER_SIZE = 4096;
258 char buffer[BUFFER_SIZE];
259 while (!src_stream.eof())
261 src_stream.read(buffer, BUFFER_SIZE);
262 if (src_stream.bad())
264 dst_stream.write(buffer, src_stream.gcount());
265 if (!dst_stream.good())
270 if (src_stream.bad())
273 if (!dst_stream.good())
282 std::size_t size = 1 << 8;
285 char* buf =
new char[size];
288 std::string ret(buf);
294 if (size > (1 << 15))
306 std::fill(path, path +
PATH_MAX,
'\0');
311# error "Unicode defined but not supported"
315 int n_chars = GetModuleFileName(
nullptr, omgwtf,
PATH_MAX);
316 std::copy(omgwtf, omgwtf + n_chars, path);
318#elif defined(__APPLE__)
325 int success = _NSGetExecutablePath(path, &pathmax);
328 throw std::runtime_error(
329 "Could not determine binary path: _NSGetExecutablePath failed!");
333 if (::realpath(path, real) ==
nullptr)
334 throw std::runtime_error(
335 "Could not determine binary path: realpath failed!");
339#elif defined(__linux) || defined(__CYGWIN__)
341 ssize_t n_chars = ::readlink(
"/proc/self/exe", path,
PATH_MAX);
344# error "Cannot determine binary path: Unsupported OS"
348 throw std::runtime_error(
"Buffer size too small!");
350 return std::string(path);
359 return path.size() >= 2 && std::isalpha(path[0]) && path[1] ==
':';
361 return path.size() >= 1 && path[0] ==
'/';
371 std::string result = path;
374 std::replace(result.begin(), result.end(),
'\\',
'/');
377 for (std::size_t i = 0; i < result.size() - 1; )
379 if (result[i] ==
'/' && result[i + 1] ==
'/')
386 if (result.size() > 1 && result[result.size() - 1] ==
'/')
387 result.erase(result.end() - 1);
393join_path (std::string
const& path1, std::string
const& path2)
400 if (!p2.empty() && p2[0] ==
'/')
420 std::size_t len = path.size();
421 while (len > 0 && path[len - 1] ==
'/')
427 while (len > 0 && path[len - 1] !=
'/')
433 while (len > 1 && path[len - 1] ==
'/')
436 return path.substr(0, len);
443 std::size_t len = path.size();
444 while (len > 0 && path[len - 1] ==
'/')
450 std::size_t base = len - 1;
451 while (base > 0 && path[base - 1] !=
'/')
454 return path.substr(base, len - base);
462 std::size_t slashpos = fn.find_last_of(
'/');
463 if (slashpos == std::string::npos)
466 std::size_t dotpos = fn.find_last_of(
'.');
467 if (dotpos == std::string::npos || dotpos < slashpos)
468 return fn +
"." + ext;
470 return fn.substr(0, dotpos) +
"." + ext;
480 std::ifstream in(filename.c_str(), std::ios::binary);
483 in.seekg(0, std::ios::end);
484 std::size_t length = in.tellg();
485 in.seekg(0, std::ios::beg);
486 data->resize(length);
487 in.read(&(*data)[0], length);
499 std::string
const& filename)
501 std::ofstream out(filename.c_str(), std::ios::binary);
504 out.write(data, len);
519File::get_absolute_name (
void)
const
523 return (!path.empty() && *path.rbegin() ==
'\\'
525 : path +
"\\" + name);
527 return (!path.empty() && *path.rbegin() ==
'/'
529 : path +
"/" + name);
536File::operator< (
File const& rhs)
const
538 if (this->is_dir && !rhs.
is_dir)
540 else if (!this->is_dir && rhs.
is_dir)
542 else if (this->path < rhs.
path)
544 else if (rhs.
path < this->path)
547 return (this->name < rhs.
name);
553Directory::scan (std::string
const& path)
558 WIN32_FIND_DATA data;
559 HANDLE hf = FindFirstFile((path +
"/*").c_str(), &data);
560 if (hf == INVALID_HANDLE_VALUE)
561 throw Exception(
"Cannot open directory");
565 if (!std::strcmp(data.cFileName,
"."))
567 if (!std::strcmp(data.cFileName,
".."))
570 this->push_back(
File());
572 this->back().name = data.cFileName;
573 this->back().is_dir =
574 (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
576 while (FindNextFile(hf, &data) != 0);
580 DIR *dp = ::opendir(path.c_str());
582 throw Exception(
"Cannot open directory: ", std::strerror(errno));
585 while ((ep = ::readdir(dp)))
587 if (!std::strcmp(ep->d_name,
"."))
589 if (!std::strcmp(ep->d_name,
".."))
591 this->push_back(
File());
592 this->back().path = path;
593 this->back().name = ep->d_name;
594 this->back().is_dir = (ep->d_type == DT_DIR);
595 if (ep->d_type == DT_UNKNOWN)
597 struct stat path_stat;
598 if (::stat(
join_path(path, ep->d_name).c_str(), &path_stat) >= 0)
599 this->back().is_dir = S_ISDIR(path_stat.st_mode);
610FileLock::FileLock (std::string
const& filename)
612 switch (this->acquire_retry(filename))
614 case LOCK_CREATED:
break;
620FileLock::acquire (std::string
const& filename)
623 this->lockfile = filename +
".lock";
624 this->reason.clear();
625 if (fs::file_exists(this->lockfile.c_str()))
627 this->reason =
"Previous lock existing";
628 return FileLock::LOCK_EXISTS;
632 std::ofstream touch(this->lockfile.c_str(), std::ios::binary);
635 this->reason =
"Error locking: ";
636 this->reason += std::strerror(errno);
637 return FileLock::LOCK_CREATE_ERROR;
642 return FileLock::LOCK_CREATED;
646FileLock::acquire_retry (std::string
const& filename,
int retries,
int sleep)
651 Status status = this->acquire(filename);
652 if (status != FileLock::LOCK_EXISTS)
655 system::sleep(sleep);
661 this->reason =
"Previous lock persisting";
662 return FileLock::LOCK_PERSISTENT;
667 return FileLock::LOCK_CREATED;
671FileLock::is_locked (std::string
const& filename)
673 std::string lockfname = filename +
".lock";
674 return fs::file_exists(lockfname.c_str());
678FileLock::wait_lock (std::string
const& filename,
int retries,
int sleep)
680 while (retries > 0 && this->is_locked(filename))
682 system::sleep(sleep);
691FileLock::release (
void)
693 if (this->lockfile.empty())
695 return fs::unlink(this->lockfile.c_str());
Universal, simple exception class.
Exception class for file exceptions with additional filename.
std::string replace_extension(std::string const &fn, std::string const &ext)
Replaces extension of the given file with 'ext'.
bool unlink(char const *pathname)
Unlinks (deletes) the given file.
std::string sanitize_path(std::string const &path)
Canonicalize slashes in the given path.
std::string abspath(std::string const &path)
Returns the absolute representation of the given path.
bool is_absolute(std::string const &path)
Checks whether the given path is absolute.
char * get_cwd(char *buf, size_t size)
bool mkdir(char const *pathname)
Creates a new directory.
void write_string_to_file(std::string const &data, std::string const &filename)
Writes the given data into a file.
bool rmdir(char const *pathname)
Removes an empty directory.
void copy_file(char const *src, char const *dst)
Copies a file from 'src' to 'dst', throws FileException on error.
bool exists(char const *pathname)
Determines if the given path is a directory.
std::string get_binary_path(void)
Returns the path of the binary currently executing.
std::string dirname(std::string const &path)
Returns the directory name component of the given path.
bool dir_exists(char const *pathname)
Determines if the given path is a directory.
char const * get_app_data_dir(void)
Determines the current user's path for application data.
bool rename(char const *from, char const *to)
Renames the given file 'from' to new name 'to'.
bool set_cwd(char const *pathname)
Changes the current working directory to 'pathname' and returns true on success.
std::string join_path(std::string const &path1, std::string const &path2)
Concatenate and canonicalize two paths.
bool file_exists(char const *pathname)
Determines if the given path is a file.
std::string basename(std::string const &path)
Returns the file name component of the given path.
void read_file_to_string(std::string const &filename, std::string *data)
Reads the whole file into a string.
char const * get_home_dir(void)
Determines the home path for the current user.
std::string get_cwd_string(void)
Determines the CWD and returns a convenient string.
#define UTIL_NAMESPACE_BEGIN
#define UTIL_NAMESPACE_END
#define UTIL_FS_NAMESPACE_BEGIN
#define UTIL_FS_NAMESPACE_END