# HG changeset patch # User David Demelier # Date 1464726812 -7200 # Node ID 0de84b31842b23a8ec798eb600c2ba8b17ad839a # Parent 7ef1aab52c1a0b1284d76c2c9c9427ebb5e7715c Irccd: update fs module diff -r 7ef1aab52c1a -r 0de84b31842b lib/irccd/fs.cpp --- a/lib/irccd/fs.cpp Tue May 31 22:29:33 2016 +0200 +++ b/lib/irccd/fs.cpp Tue May 31 22:33:32 2016 +0200 @@ -16,7 +16,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if defined(_WIN32) +# define _CRT_SECURE_NO_WARNINGS +#endif + #include +#include #include #include #include @@ -41,6 +46,12 @@ namespace { +/* + * error. + * ------------------------------------------------------------------ + * + * Function to retrieve system error in Windows API. + */ #if defined(_WIN32) std::string error() @@ -65,8 +76,17 @@ #endif -bool can(const std::string &path, const std::string &mode) +/* + * hasAccess. + * ------------------------------------------------------------------ + * + * Check if we have access to the file specified, mode is the same used as std::fopen. + */ +bool hasAccess(const std::string &path, const std::string &mode) { + assert(mode.length() == 1); + assert(mode[0] == 'r' || mode[0] == 'w'); + auto fp = std::fopen(path.c_str(), mode.c_str()); if (fp == nullptr) @@ -77,22 +97,33 @@ return true; } +/* + * typeOf. + * ------------------------------------------------------------------ + * + * Get the type of the specified file. + * + * Use GetFileAttributesA on Windows and stat if available. + * + * Receives the object as predicate parameter and return true on success. + */ #if defined(_WIN32) -bool is(const std::string &path, DWORD flags) +template +bool typeOf(const std::string &path, Predicate &&predicate) { - DWORD result = GetFileAttributes(path.c_str()); + DWORD result = GetFileAttributesA(path.c_str()); if (result == INVALID_FILE_ATTRIBUTES) return false; - return result & flags; + return predicate(result); } -#else +#elif defined(FS_HAVE_STAT) template -bool is(const std::string &path, Predicate &&predicate) noexcept +bool typeOf(const std::string &path, Predicate &&predicate) noexcept { struct stat st; @@ -102,26 +133,39 @@ return predicate(st); } +#else + +template +bool typeOf(const std::string &path, Predicate &&predicate) noexcept +{ + throw std::runtime_error(std::strerror(ENOSYS)); +} + #endif } // !namespace +/* + * clean. + * ------------------------------------------------------------------ + */ std::string clean(std::string input) { if (input.empty()) return input; - // First, remove any duplicates. + /* First, remove any duplicates */ input.erase(std::unique(input.begin(), input.end(), [&] (char c1, char c2) { return c1 == c2 && (c1 == '/' || c1 == '\\'); }), input.end()); - // Add a trailing / or \\. + /* Add a trailing / or \\ */ char c = input[input.length() - 1]; + if (c != '/' && c != '\\') input += separator(); - // Now converts all / to \\ for Windows and the opposite for Unix. + /* Now converts all / to \\ for Windows and the opposite for Unix */ #if defined(_WIN32) std::replace(input.begin(), input.end(), '/', '\\'); #else @@ -131,6 +175,10 @@ return input; } +/* + * baseName. + * ------------------------------------------------------------------ + */ std::string baseName(std::string path) { auto pos = path.find_last_of("\\/"); @@ -141,11 +189,15 @@ return path; } +/* + * dirName. + * ------------------------------------------------------------------ + */ std::string dirName(std::string path) { auto pos = path.find_last_of("\\/"); - if (pos == std::string::npos) + if (pos == std::string::npos) path = "."; else path = path.substr(0, pos); @@ -153,6 +205,10 @@ return path; } +/* + * isAbsolute. + * ------------------------------------------------------------------ + */ bool isAbsolute(const std::string &path) noexcept { #if defined(_WIN32) @@ -162,51 +218,87 @@ #endif } +/* + * isRelative. + * ------------------------------------------------------------------ + */ bool isRelative(const std::string &path) noexcept { #if defined(_WIN32) - return PathIsRelativeA(path.c_str()); + return PathIsRelativeA(path.c_str()) == 1; #else return !isAbsolute(path); #endif } +/* + * isReadable. + * ------------------------------------------------------------------ + */ bool isReadable(const std::string &path) noexcept { - return can(path, "r"); + return hasAccess(path, "r"); +} + +/* + * isWritable. + * ------------------------------------------------------------------ + */ +bool isWritable(const std::string &path) noexcept +{ + return hasAccess(path, "w"); } -bool isWritable(const std::string &path) noexcept +/* + * isFile. + * ------------------------------------------------------------------ + */ +bool isFile(const std::string &path) { - return can(path, "w"); + return typeOf(path, [] (const auto &object) { +#if defined(_WIN32) + return (object & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE; +#elif defined(FS_HAVE_STAT) + return S_ISREG(object.st_mode); +#endif + }); } -bool isFile(const std::string &path) noexcept +/* + * isDirectory. + * ------------------------------------------------------------------ + */ +bool isDirectory(const std::string &path) { + return typeOf(path, [] (const auto &object) { #if defined(_WIN32) - return is(path, FILE_ATTRIBUTE_ARCHIVE); -#else - return is(path, [] (const struct stat &st) { return S_ISREG(st.st_mode); }); + return (object & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; +#elif defined(FS_HAVE_STAT) + return S_ISDIR(object.st_mode); #endif + }); } -bool isDirectory(const std::string &path) noexcept +/* + * isSymlink. + * ------------------------------------------------------------------ + */ +bool isSymlink(const std::string &path) { + return typeOf(path, [] (const auto &object) { #if defined(_WIN32) - return is(path, FILE_ATTRIBUTE_DIRECTORY); -#else - return is(path, [] (const struct stat &st) { return S_ISDIR(st.st_mode); }); + return (object & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT; +#elif defined(FS_HAVE_STAT) + return S_ISLNK(object.st_mode); #endif + }); } -bool isSymlink(const std::string &path) noexcept -{ -#if defined(_WIN32) - return is(path, FILE_ATTRIBUTE_REPARSE_POINT); -#else - return is(path, [] (const struct stat &st) { return S_ISLNK(st.st_mode); }); -#endif -} +/* + * stat. + * ------------------------------------------------------------------ + */ +#if defined(FS_HAVE_STAT) struct stat stat(const std::string &path) { @@ -218,17 +310,27 @@ return st; } +#endif + +/* + * exists. + * ------------------------------------------------------------------ + */ bool exists(const std::string &path) noexcept { -#if defined(HAVE_ACCESS) - return ::access(path.c_str(), F_OK) == 0; -#else +#if defined(FS_HAVE_STAT) struct stat st; return ::stat(path.c_str(), &st) == 0; +#else + return hasAccess(path, "r"); #endif } +/* + * readdir. + * ------------------------------------------------------------------ + */ std::vector readdir(const std::string &path, int flags) { std::vector entries; @@ -242,7 +344,7 @@ handle = FindFirstFile(oss.str().c_str(), &fdata); if (handle == nullptr) - throw std::runtime_error{error()}; + throw std::runtime_error(error()); do { Entry entry; @@ -311,6 +413,10 @@ return entries; } +/* + * mkdir. + * ------------------------------------------------------------------ + */ void mkdir(const std::string &path, int mode) { std::string::size_type next = 0; @@ -337,6 +443,10 @@ } } +/* + * rmdir. + * ------------------------------------------------------------------ + */ void rmdir(const std::string &base) noexcept { try { @@ -346,25 +456,29 @@ if (entry.type == Entry::Dir) rmdir(path); else - (void)::remove(path.c_str()); + remove(path.c_str()); } } catch (...) { } #if defined(_WIN32) - RemoveDirectory(base.c_str()); + RemoveDirectoryA(base.c_str()); #else - (void)::remove(base.c_str()); + remove(base.c_str()); #endif } +/* + * cwd. + * ------------------------------------------------------------------ + */ std::string cwd() { #if defined(_WIN32) char path[MAX_PATH]; if (!GetCurrentDirectoryA(sizeof (path), path)) - throw std::runtime_error{"failed to get current working directory"}; + throw std::runtime_error("failed to get current working directory"); return path; #else diff -r 7ef1aab52c1a -r 0de84b31842b lib/irccd/fs.hpp --- a/lib/irccd/fs.hpp Tue May 31 22:29:33 2016 +0200 +++ b/lib/irccd/fs.hpp Tue May 31 22:33:32 2016 +0200 @@ -22,15 +22,32 @@ /** * \file fs.hpp * \brief Filesystem operations made easy. + */ + +/** + * \page filesystem Filesystem + * \brief Filesystem support * * The following options can be set by the user: * - * - **HAVE_ACCESS**: (bool) Set to true if unistd.h file and access(2) function are available. - * - * On Windows, you must link to shlwapi library. + * - **FS_HAVE_STAT**: (bool) Set to true if sys/stat.h and stat function are available, automatically detected. */ -#include +#if !defined(FS_HAVE_STAT) +# if defined(_WIN32) +# define FS_HAVE_STAT +# elif defined(__linux__) +# define FS_HAVE_STAT +# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define FS_HAVE_STAT +# elif defined(__APPLE__) +# define FS_HAVE_STAT +# endif +#endif + +#if defined(FS_HAVE_STAT) +# include +#endif #include #include @@ -40,6 +57,9 @@ namespace irccd { +/** + * \brief Filesystem namespace. + */ namespace fs { /** @@ -72,6 +92,30 @@ }; /** + * Check if two entries are identical. + * + * \param e1 the first entry + * \param e2 the second entry + * \return true if they are identical + */ +inline bool operator==(const Entry &e1, const Entry &e2) noexcept +{ + return e1.name == e2.name && e1.type == e2.type; +} + +/** + * Check if two entries are different. + * + * \param e1 the first entry + * \param e2 the second entry + * \return true if they are different + */ +inline bool operator!=(const Entry &e1, const Entry &e2) noexcept +{ + return !(e1 == e2); +} + +/** * Get the separator for that system. * * \return \ on Windows and / otherwise @@ -113,6 +157,8 @@ */ IRCCD_EXPORT std::string dirName(std::string path); +#if defined(FS_HAVE_STAT) + /** * Get stat information. * @@ -122,6 +168,8 @@ */ IRCCD_EXPORT struct stat stat(const std::string &path); +#endif // !HAVE_STAT + /** * Check if a file exists. * @@ -169,24 +217,27 @@ * * \param path the path * \return true if it is a file and false if not or not readable + * \throw std::runtime_error if the operation is not supported */ -IRCCD_EXPORT bool isFile(const std::string &path) noexcept; +IRCCD_EXPORT bool isFile(const std::string &path); /** * Check if the file is a directory. * * \param path the path * \return true if it is a directory and false if not or not readable + * \throw std::runtime_error if the operation is not supported */ -IRCCD_EXPORT bool isDirectory(const std::string &path) noexcept; +IRCCD_EXPORT bool isDirectory(const std::string &path); /** * Check if the file is a symbolic link. * * \param path the path * \return true if it is a symbolic link and false if not or not readable + * \throw std::runtime_error if the operation is not supported */ -IRCCD_EXPORT bool isSymlink(const std::string &path) noexcept; +IRCCD_EXPORT bool isSymlink(const std::string &path); /** * Read a directory and return a list of entries (not recursive). @@ -249,15 +300,17 @@ } } - if (path.empty()) { - for (const auto &entry : entries) { - if (entry.type == Entry::Dir) { - path = findIf(base + separator() + entry.name, std::forward(predicate)); + if (!path.empty()) + return path; - if (!path.empty()) - break; - } - } + for (const auto &entry : entries) { + if (entry.type != Entry::Dir) + continue; + + path = findIf(base + separator() + entry.name, std::forward(predicate)); + + if (!path.empty()) + break; } return path;