diff options
Diffstat (limited to 'src/fs')
-rw-r--r-- | src/fs/AllocatedPath.cxx | 113 | ||||
-rw-r--r-- | src/fs/AllocatedPath.hxx | 226 | ||||
-rw-r--r-- | src/fs/DirectoryReader.hxx | 8 | ||||
-rw-r--r-- | src/fs/FileSystem.cxx | 12 | ||||
-rw-r--r-- | src/fs/FileSystem.hxx | 37 | ||||
-rw-r--r-- | src/fs/Path.cxx | 64 | ||||
-rw-r--r-- | src/fs/Path.hxx | 106 |
7 files changed, 392 insertions, 174 deletions
diff --git a/src/fs/AllocatedPath.cxx b/src/fs/AllocatedPath.cxx new file mode 100644 index 000000000..37b79a685 --- /dev/null +++ b/src/fs/AllocatedPath.cxx @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "AllocatedPath.hxx" +#include "Domain.hxx" +#include "Charset.hxx" +#include "util/Error.hxx" +#include "Compiler.h" + +#include <glib.h> + +#include <assert.h> +#include <string.h> + +inline AllocatedPath::AllocatedPath(Donate, pointer _value) + :value(_value) { + g_free(_value); +} + +/* no inlining, please */ +AllocatedPath::~AllocatedPath() {} + +AllocatedPath +AllocatedPath::Build(const_pointer a, const_pointer b) +{ + return AllocatedPath(Donate(), g_build_filename(a, b, nullptr)); +} + +AllocatedPath +AllocatedPath::FromUTF8(const char *path_utf8) +{ + return AllocatedPath(Donate(), ::PathFromUTF8(path_utf8)); +} + +AllocatedPath +AllocatedPath::FromUTF8(const char *path_utf8, Error &error) +{ + AllocatedPath path = FromUTF8(path_utf8); + if (path.IsNull()) + error.Format(path_domain, + "Failed to convert to file system charset: %s", + path_utf8); + + return path; +} + +AllocatedPath +AllocatedPath::GetDirectoryName() const +{ + return AllocatedPath(Donate(), g_path_get_dirname(c_str())); +} + +std::string +AllocatedPath::ToUTF8() const +{ + return ::PathToUTF8(c_str()); +} + +const char * +AllocatedPath::RelativeFS(const char *other_fs) const +{ + const size_t l = length(); + if (memcmp(data(), other_fs, l) != 0) + return nullptr; + + other_fs += l; + if (*other_fs != 0) { + if (!PathTraits::IsSeparatorFS(*other_fs)) + /* mismatch */ + return nullptr; + + /* skip remaining path separators */ + do { + ++other_fs; + } while (PathTraits::IsSeparatorFS(*other_fs)); + } + + return other_fs; +} + +void +AllocatedPath::ChopSeparators() +{ + size_t l = length(); + const char *p = data(); + + while (l >= 2 && PathTraits::IsSeparatorFS(p[l - 1])) { + --l; + +#if GCC_CHECK_VERSION(4,7) && !defined(__clang__) + value.pop_back(); +#else + value.erase(value.end() - 1, value.end()); +#endif + } +} diff --git a/src/fs/AllocatedPath.hxx b/src/fs/AllocatedPath.hxx new file mode 100644 index 000000000..1655a270a --- /dev/null +++ b/src/fs/AllocatedPath.hxx @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_FS_ALLOCATED_PATH_HXX +#define MPD_FS_ALLOCATED_PATH_HXX + +#include "check.h" +#include "Compiler.h" +#include "Traits.hxx" +#include "Path.hxx" + +#ifdef WIN32 +#include <glib.h> +#endif + +#include <utility> +#include <string> + +#include <assert.h> + +class Error; + +/** + * A path name in the native file system character set. + * + * This class manages the memory chunk where this path string is + * stored. + */ +class AllocatedPath { + typedef std::string string; + + typedef PathTraits::value_type value_type; + typedef PathTraits::pointer pointer; + typedef PathTraits::const_pointer const_pointer; + + string value; + + struct Donate {}; + + /** + * Donate the allocated pointer to a new #AllocatedPath object. + */ + AllocatedPath(Donate, pointer _value); + + AllocatedPath(const_pointer _value):value(_value) {} + +public: + /** + * Copy a #AllocatedPath object. + */ + AllocatedPath(const AllocatedPath &) = default; + + /** + * Move a #AllocatedPath object. + */ + AllocatedPath(AllocatedPath &&other):value(std::move(other.value)) {} + + ~AllocatedPath(); + + /** + * Return a "nulled" instance. Its IsNull() method will + * return true. Such an object must not be used. + * + * @see IsNull() + */ + gcc_const + static AllocatedPath Null() { + return AllocatedPath(""); + } + + gcc_pure + operator Path() const { + return Path::FromFS(c_str()); + } + + /** + * Join two path components with the path separator. + */ + gcc_pure gcc_nonnull_all + static AllocatedPath Build(const_pointer a, const_pointer b); + + gcc_pure gcc_nonnull_all + static AllocatedPath Build(const_pointer a, const AllocatedPath &b) { + return Build(a, b.c_str()); + } + + gcc_pure gcc_nonnull_all + static AllocatedPath Build(const AllocatedPath &a, const_pointer b) { + return Build(a.c_str(), b); + } + + gcc_pure + static AllocatedPath Build(const AllocatedPath &a, + const AllocatedPath &b) { + return Build(a.c_str(), b.c_str()); + } + + /** + * Convert a C string that is already in the filesystem + * character set to a #Path instance. + */ + gcc_pure + static AllocatedPath FromFS(const_pointer fs) { + return AllocatedPath(fs); + } + + /** + * Convert a UTF-8 C string to a #AllocatedPath instance. + * Returns return a "nulled" instance on error. + */ + gcc_pure gcc_nonnull_all + static AllocatedPath FromUTF8(const char *path_utf8); + + gcc_pure gcc_nonnull_all + static AllocatedPath FromUTF8(const char *path_utf8, Error &error); + + /** + * Copy a #AllocatedPath object. + */ + AllocatedPath &operator=(const AllocatedPath &) = default; + + /** + * Move a #AllocatedPath object. + */ + AllocatedPath &operator=(AllocatedPath &&other) { + value = std::move(other.value); + return *this; + } + + /** + * Check if this is a "nulled" instance. A "nulled" instance + * must not be used. + */ + bool IsNull() const { + return value.empty(); + } + + /** + * Clear this object's value, make it "nulled". + * + * @see IsNull() + */ + void SetNull() { + value.clear(); + } + + /** + * @return the length of this string in number of "value_type" + * elements (which may not be the number of characters). + */ + gcc_pure + size_t length() const { + return value.length(); + } + + /** + * Returns the value as a const C string. The returned + * pointer is invalidated whenever the value of life of this + * instance ends. + */ + gcc_pure + const_pointer c_str() const { + return value.c_str(); + } + + /** + * Returns a pointer to the raw value, not necessarily + * null-terminated. + */ + gcc_pure + const_pointer data() const { + return value.data(); + } + + /** + * Convert the path to UTF-8. + * Returns empty string on error or if this instance is "nulled" + * (#IsNull returns true). + */ + gcc_pure + std::string ToUTF8() const; + + /** + * Gets directory name of this path. + * Returns a "nulled" instance on error. + */ + gcc_pure + AllocatedPath GetDirectoryName() const; + + /** + * Determine the relative part of the given path to this + * object, not including the directory separator. Returns an + * empty string if the given path equals this object or + * nullptr on mismatch. + */ + gcc_pure + const char *RelativeFS(const char *other_fs) const; + + /** + * Chop trailing directory separators. + */ + void ChopSeparators(); + + gcc_pure + bool IsAbsolute() { + return PathTraits::IsAbsoluteFS(c_str()); + } +}; + +#endif diff --git a/src/fs/DirectoryReader.hxx b/src/fs/DirectoryReader.hxx index 4e4a56345..c9d2c04b8 100644 --- a/src/fs/DirectoryReader.hxx +++ b/src/fs/DirectoryReader.hxx @@ -21,7 +21,7 @@ #define MPD_FS_DIRECTORY_READER_HXX #include "check.h" -#include "Path.hxx" +#include "AllocatedPath.hxx" #include <dirent.h> @@ -35,7 +35,7 @@ public: /** * Creates new directory reader for the specified #dir. */ - explicit DirectoryReader(const Path &dir) + explicit DirectoryReader(Path dir) : dirp(opendir(dir.c_str())), ent(nullptr) { } @@ -78,9 +78,9 @@ public: /** * Extracts directory entry that was previously read by #ReadEntry. */ - Path GetEntry() const { + AllocatedPath GetEntry() const { assert(HasEntry()); - return Path::FromFS(ent->d_name); + return AllocatedPath::FromFS(ent->d_name); } }; diff --git a/src/fs/FileSystem.cxx b/src/fs/FileSystem.cxx index 7f740e3af..4cd9f33b2 100644 --- a/src/fs/FileSystem.cxx +++ b/src/fs/FileSystem.cxx @@ -19,26 +19,28 @@ #include "config.h" #include "FileSystem.hxx" +#include "AllocatedPath.hxx" #include "Limits.hxx" #include <errno.h> -Path ReadLink(const Path &path) +AllocatedPath +ReadLink(Path path) { #ifdef WIN32 (void)path; errno = EINVAL; - return Path::Null(); + return AllocatedPath::Null(); #else char buffer[MPD_PATH_MAX]; ssize_t size = readlink(path.c_str(), buffer, MPD_PATH_MAX); if (size < 0) - return Path::Null(); + return AllocatedPath::Null(); if (size_t(size) >= MPD_PATH_MAX) { errno = ENOMEM; - return Path::Null(); + return AllocatedPath::Null(); } buffer[size] = '\0'; - return Path::FromFS(buffer); + return AllocatedPath::FromFS(buffer); #endif } diff --git a/src/fs/FileSystem.hxx b/src/fs/FileSystem.hxx index faa00751a..cb2f82d22 100644 --- a/src/fs/FileSystem.hxx +++ b/src/fs/FileSystem.hxx @@ -31,6 +31,8 @@ #include <assert.h> #include <stdio.h> +class AllocatedPath; + namespace FOpenMode { /** * Open mode for reading text files. @@ -67,7 +69,7 @@ namespace FOpenMode { * Wrapper for fopen() that uses #Path names. */ static inline FILE * -FOpen(const Path &file, PathTraits::const_pointer mode) +FOpen(Path file, PathTraits::const_pointer mode) { return fopen(file.c_str(), mode); } @@ -75,7 +77,8 @@ FOpen(const Path &file, PathTraits::const_pointer mode) /** * Wrapper for open_cloexec() that uses #Path names. */ -static inline int OpenFile(const Path &file, int flags, int mode) +static inline int +OpenFile(Path file, int flags, int mode) { return open_cloexec(file.c_str(), flags, mode); } @@ -83,7 +86,8 @@ static inline int OpenFile(const Path &file, int flags, int mode) /** * Wrapper for rename() that uses #Path names. */ -static inline bool RenameFile(const Path &oldpath, const Path &newpath) +static inline bool +RenameFile(Path oldpath, Path newpath) { return rename(oldpath.c_str(), newpath.c_str()) == 0; } @@ -91,8 +95,8 @@ static inline bool RenameFile(const Path &oldpath, const Path &newpath) /** * Wrapper for stat() that uses #Path names. */ -static inline bool StatFile(const Path &file, struct stat &buf, - bool follow_symlinks = true) +static inline bool +StatFile(Path file, struct stat &buf, bool follow_symlinks = true) { #ifdef WIN32 (void)follow_symlinks; @@ -108,7 +112,8 @@ static inline bool StatFile(const Path &file, struct stat &buf, /** * Wrapper for unlink() that uses #Path names. */ -static inline bool RemoveFile(const Path &file) +static inline bool +RemoveFile(Path file) { return unlink(file.c_str()) == 0; } @@ -116,12 +121,13 @@ static inline bool RemoveFile(const Path &file) /** * Wrapper for readlink() that uses #Path names. */ -Path ReadLink(const Path &path); +AllocatedPath +ReadLink(Path path); #ifndef WIN32 static inline bool -MakeFifo(const Path &path, mode_t mode) +MakeFifo(Path path, mode_t mode) { return mkfifo(path.c_str(), mode) == 0; } @@ -131,7 +137,8 @@ MakeFifo(const Path &path, mode_t mode) /** * Wrapper for access() that uses #Path names. */ -static inline bool CheckAccess(const Path &path, int mode) +static inline bool +CheckAccess(Path path, int mode) { #ifdef WIN32 (void)path; @@ -145,8 +152,8 @@ static inline bool CheckAccess(const Path &path, int mode) /** * Checks if #Path exists and is a regular file. */ -static inline bool FileExists(const Path &path, - bool follow_symlinks = true) +static inline bool +FileExists(Path path, bool follow_symlinks = true) { struct stat buf; return StatFile(path, buf, follow_symlinks) && S_ISREG(buf.st_mode); @@ -155,8 +162,8 @@ static inline bool FileExists(const Path &path, /** * Checks if #Path exists and is a directory. */ -static inline bool DirectoryExists(const Path &path, - bool follow_symlinks = true) +static inline bool +DirectoryExists(Path path, bool follow_symlinks = true) { struct stat buf; return StatFile(path, buf, follow_symlinks) && S_ISDIR(buf.st_mode); @@ -165,8 +172,8 @@ static inline bool DirectoryExists(const Path &path, /** * Checks if #Path exists. */ -static inline bool PathExists(const Path &path, - bool follow_symlinks = true) +static inline bool +PathExists(Path path, bool follow_symlinks = true) { struct stat buf; return StatFile(path, buf, follow_symlinks); diff --git a/src/fs/Path.cxx b/src/fs/Path.cxx index ecdf73e49..0ff0591fb 100644 --- a/src/fs/Path.cxx +++ b/src/fs/Path.cxx @@ -19,57 +19,12 @@ #include "config.h" #include "Path.hxx" -#include "Domain.hxx" #include "Charset.hxx" -#include "util/Error.hxx" -#include "Compiler.h" - -#include <glib.h> - -#include <assert.h> -#include <string.h> - -inline Path::Path(Donate, pointer _value) - :value(_value) { - g_free(_value); -} - -/* no inlining, please */ -Path::~Path() {} - -Path -Path::Build(const_pointer a, const_pointer b) -{ - return Path(Donate(), g_build_filename(a, b, nullptr)); -} - -Path Path::FromUTF8(const char *path_utf8) -{ - return Path(Donate(), ::PathFromUTF8(path_utf8)); -} - -Path -Path::FromUTF8(const char *path_utf8, Error &error) -{ - Path path = FromUTF8(path_utf8); - if (path.IsNull()) - error.Format(path_domain, - "Failed to convert to file system charset: %s", - path_utf8); - - return path; -} - -Path -Path::GetDirectoryName() const -{ - return Path(Donate(), g_path_get_dirname(value.c_str())); -} std::string Path::ToUTF8() const { - return ::PathToUTF8(value.c_str()); + return ::PathToUTF8(c_str()); } const char * @@ -93,20 +48,3 @@ Path::RelativeFS(const char *other_fs) const return other_fs; } - -void -Path::ChopSeparators() -{ - size_t l = length(); - const char *p = data(); - - while (l >= 2 && PathTraits::IsSeparatorFS(p[l - 1])) { - --l; - -#if GCC_CHECK_VERSION(4,7) && !defined(__clang__) - value.pop_back(); -#else - value.erase(value.end() - 1, value.end()); -#endif - } -} diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx index 558e2923f..6ea954577 100644 --- a/src/fs/Path.hxx +++ b/src/fs/Path.hxx @@ -24,50 +24,33 @@ #include "Compiler.h" #include "Traits.hxx" -#ifdef WIN32 -#include <glib.h> -#endif - -#include <utility> #include <string> #include <assert.h> +#include <string.h> class Error; /** * A path name in the native file system character set. + * + * This class manages a pointer to an existing path string. While an + * instance lives, the string must not be invalidated. */ class Path { - typedef std::string string; - typedef PathTraits::value_type value_type; typedef PathTraits::pointer pointer; typedef PathTraits::const_pointer const_pointer; - string value; - - struct Donate {}; + const char *value; - /** - * Donate the allocated pointer to a new #Path object. - */ - Path(Donate, pointer _value); - - Path(const_pointer _value):value(_value) {} + constexpr Path(const_pointer _value):value(_value) {} public: /** * Copy a #Path object. */ - Path(const Path &) = default; - - /** - * Move a #Path object. - */ - Path(Path &&other):value(std::move(other.value)) {} - - ~Path(); + constexpr Path(const Path &) = default; /** * Return a "nulled" instance. Its IsNull() method will @@ -75,70 +58,29 @@ public: * * @see IsNull() */ - gcc_const - static Path Null() { - return Path(""); + static constexpr Path Null() { + return Path(nullptr); } /** - * Join two path components with the path separator. + * Create a new instance pointing to the specified path + * string. */ - gcc_pure gcc_nonnull_all - static Path Build(const_pointer a, const_pointer b); - - gcc_pure gcc_nonnull_all - static Path Build(const_pointer a, const Path &b) { - return Build(a, b.c_str()); - } - - gcc_pure gcc_nonnull_all - static Path Build(const Path &a, const_pointer b) { - return Build(a.c_str(), b); - } - - gcc_pure - static Path Build(const Path &a, const Path &b) { - return Build(a.c_str(), b.c_str()); - } - - /** - * Convert a C string that is already in the filesystem - * character set to a #Path instance. - */ - gcc_pure - static Path FromFS(const_pointer fs) { + static constexpr Path FromFS(const_pointer fs) { return Path(fs); } /** - * Convert a UTF-8 C string to a #Path instance. - * Returns return a "nulled" instance on error. - */ - gcc_pure gcc_nonnull_all - static Path FromUTF8(const char *path_utf8); - - gcc_pure gcc_nonnull_all - static Path FromUTF8(const char *path_utf8, Error &error); - - /** * Copy a #Path object. */ Path &operator=(const Path &) = default; /** - * Move a #Path object. - */ - Path &operator=(Path &&other) { - value = std::move(other.value); - return *this; - } - - /** * Check if this is a "nulled" instance. A "nulled" instance * must not be used. */ bool IsNull() const { - return value.empty(); + return value == nullptr; } /** @@ -147,7 +89,7 @@ public: * @see IsNull() */ void SetNull() { - value.clear(); + value = nullptr; } /** @@ -156,7 +98,9 @@ public: */ gcc_pure size_t length() const { - return value.length(); + assert(value != nullptr); + + return strlen(value); } /** @@ -166,7 +110,7 @@ public: */ gcc_pure const_pointer c_str() const { - return value.c_str(); + return value; } /** @@ -175,7 +119,7 @@ public: */ gcc_pure const_pointer data() const { - return value.data(); + return value; } /** @@ -187,13 +131,6 @@ public: std::string ToUTF8() const; /** - * Gets directory name of this path. - * Returns a "nulled" instance on error. - */ - gcc_pure - Path GetDirectoryName() const; - - /** * Determine the relative part of the given path to this * object, not including the directory separator. Returns an * empty string if the given path equals this object or @@ -202,11 +139,6 @@ public: gcc_pure const char *RelativeFS(const char *other_fs) const; - /** - * Chop trailing directory separators. - */ - void ChopSeparators(); - gcc_pure bool IsAbsolute() { return PathTraits::IsAbsoluteFS(c_str()); |