aboutsummaryrefslogtreecommitdiffstats
path: root/src/fs
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs')
-rw-r--r--src/fs/AllocatedPath.cxx27
-rw-r--r--src/fs/AllocatedPath.hxx56
-rw-r--r--src/fs/Charset.cxx48
-rw-r--r--src/fs/Charset.hxx2
-rw-r--r--src/fs/CheckFile.cxx62
-rw-r--r--src/fs/CheckFile.hxx34
-rw-r--r--src/fs/Config.cxx16
-rw-r--r--src/fs/Config.hxx2
-rw-r--r--src/fs/DirectoryReader.hxx8
-rw-r--r--src/fs/Domain.cxx2
-rw-r--r--src/fs/Domain.hxx2
-rw-r--r--src/fs/FileSystem.cxx2
-rw-r--r--src/fs/FileSystem.hxx37
-rw-r--r--src/fs/Limits.hxx2
-rw-r--r--src/fs/Path.cxx24
-rw-r--r--src/fs/Path.hxx16
-rw-r--r--src/fs/StandardDirectory.cxx294
-rw-r--r--src/fs/StandardDirectory.hxx64
-rw-r--r--src/fs/TextFile.cxx81
-rw-r--r--src/fs/TextFile.hxx62
-rw-r--r--src/fs/Traits.cxx136
-rw-r--r--src/fs/Traits.hxx168
22 files changed, 1007 insertions, 138 deletions
diff --git a/src/fs/AllocatedPath.cxx b/src/fs/AllocatedPath.cxx
index 37b79a685..30ce7e3a9 100644
--- a/src/fs/AllocatedPath.cxx
+++ b/src/fs/AllocatedPath.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,29 +24,32 @@
#include "util/Error.hxx"
#include "Compiler.h"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
-#include <assert.h>
#include <string.h>
+#ifdef HAVE_GLIB
+
inline AllocatedPath::AllocatedPath(Donate, pointer _value)
:value(_value) {
g_free(_value);
}
+#endif
+
/* 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)
{
+#ifdef HAVE_GLIB
return AllocatedPath(Donate(), ::PathFromUTF8(path_utf8));
+#else
+ return FromFS(path_utf8);
+#endif
}
AllocatedPath
@@ -64,7 +67,7 @@ AllocatedPath::FromUTF8(const char *path_utf8, Error &error)
AllocatedPath
AllocatedPath::GetDirectoryName() const
{
- return AllocatedPath(Donate(), g_path_get_dirname(c_str()));
+ return FromFS(PathTraitsFS::GetParent(c_str()));
}
std::string
@@ -82,14 +85,14 @@ AllocatedPath::RelativeFS(const char *other_fs) const
other_fs += l;
if (*other_fs != 0) {
- if (!PathTraits::IsSeparatorFS(*other_fs))
+ if (!PathTraitsFS::IsSeparator(*other_fs))
/* mismatch */
return nullptr;
/* skip remaining path separators */
do {
++other_fs;
- } while (PathTraits::IsSeparatorFS(*other_fs));
+ } while (PathTraitsFS::IsSeparator(*other_fs));
}
return other_fs;
@@ -101,7 +104,7 @@ AllocatedPath::ChopSeparators()
size_t l = length();
const char *p = data();
- while (l >= 2 && PathTraits::IsSeparatorFS(p[l - 1])) {
+ while (l >= 2 && PathTraitsFS::IsSeparator(p[l - 1])) {
--l;
#if GCC_CHECK_VERSION(4,7) && !defined(__clang__)
diff --git a/src/fs/AllocatedPath.hxx b/src/fs/AllocatedPath.hxx
index 36d8a1598..4fb217547 100644
--- a/src/fs/AllocatedPath.hxx
+++ b/src/fs/AllocatedPath.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,8 +28,6 @@
#include <utility>
#include <string>
-#include <assert.h>
-
class Error;
/**
@@ -39,11 +37,10 @@ class Error;
* stored.
*/
class AllocatedPath {
- typedef std::string string;
-
- typedef PathTraits::value_type value_type;
- typedef PathTraits::pointer pointer;
- typedef PathTraits::const_pointer const_pointer;
+ typedef PathTraitsFS::string string;
+ typedef PathTraitsFS::value_type value_type;
+ typedef PathTraitsFS::pointer pointer;
+ typedef PathTraitsFS::const_pointer const_pointer;
string value;
@@ -56,6 +53,12 @@ class AllocatedPath {
AllocatedPath(const_pointer _value):value(_value) {}
+ AllocatedPath(string &&_value):value(std::move(_value)) {}
+
+ static AllocatedPath Build(const_pointer a, size_t a_size,
+ const_pointer b, size_t b_size) {
+ return AllocatedPath(PathTraitsFS::Build(a, a_size, b, b_size));
+ }
public:
/**
* Copy a #AllocatedPath object.
@@ -67,6 +70,8 @@ public:
*/
AllocatedPath(AllocatedPath &&other):value(std::move(other.value)) {}
+ explicit AllocatedPath(Path other):value(other.c_str()) {}
+
~AllocatedPath();
/**
@@ -89,22 +94,38 @@ public:
* Join two path components with the path separator.
*/
gcc_pure gcc_nonnull_all
- static AllocatedPath Build(const_pointer a, const_pointer b);
+ static AllocatedPath Build(const_pointer a, const_pointer b) {
+ return Build(a, PathTraitsFS::GetLength(a),
+ b, PathTraitsFS::GetLength(b));
+ }
gcc_pure gcc_nonnull_all
- static AllocatedPath Build(const_pointer a, const AllocatedPath &b) {
+ static AllocatedPath Build(Path a, const_pointer b) {
+ return Build(a.c_str(), b);
+ }
+
+ gcc_pure gcc_nonnull_all
+ static AllocatedPath Build(Path a, Path b) {
return Build(a, b.c_str());
}
gcc_pure gcc_nonnull_all
+ static AllocatedPath Build(const_pointer a, const AllocatedPath &b) {
+ return Build(a, PathTraitsFS::GetLength(a),
+ b.value.c_str(), b.value.size());
+ }
+
+ gcc_pure gcc_nonnull_all
static AllocatedPath Build(const AllocatedPath &a, const_pointer b) {
- return Build(a.c_str(), b);
+ return Build(a.value.c_str(), a.value.size(),
+ b, PathTraitsFS::GetLength(b));
}
gcc_pure
static AllocatedPath Build(const AllocatedPath &a,
const AllocatedPath &b) {
- return Build(a.c_str(), b.c_str());
+ return Build(a.value.c_str(), a.value.size(),
+ b.value.c_str(), b.value.size());
}
/**
@@ -117,6 +138,15 @@ public:
}
/**
+ * Convert a C++ string that is already in the filesystem
+ * character set to a #Path instance.
+ */
+ gcc_pure
+ static AllocatedPath FromFS(string &&fs) {
+ return AllocatedPath(std::move(fs));
+ }
+
+ /**
* Convert a UTF-8 C string to a #AllocatedPath instance.
* Returns return a "nulled" instance on error.
*/
@@ -215,7 +245,7 @@ public:
gcc_pure
bool IsAbsolute() {
- return PathTraits::IsAbsoluteFS(c_str());
+ return PathTraitsFS::IsAbsolute(c_str());
}
};
diff --git a/src/fs/Charset.cxx b/src/fs/Charset.cxx
index dad5779f9..232a9a23c 100644
--- a/src/fs/Charset.cxx
+++ b/src/fs/Charset.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,11 +22,14 @@
#include "Domain.hxx"
#include "Limits.hxx"
#include "system/FatalError.hxx"
-#include "util/Error.hxx"
-#include "util/Domain.hxx"
#include "Log.hxx"
+#include "Traits.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
+
+#include <algorithm>
#include <assert.h>
#include <string.h>
@@ -41,6 +44,7 @@
*/
static constexpr size_t MPD_PATH_MAX_UTF8 = (MPD_PATH_MAX - 1) * 4 + 1;
+#ifdef HAVE_GLIB
static std::string fs_charset;
gcc_pure
@@ -70,10 +74,29 @@ SetFSCharset(const char *charset)
"SetFSCharset: fs charset is: %s", fs_charset.c_str());
}
+#endif
+
const char *
GetFSCharset()
{
+#ifdef HAVE_GLIB
return fs_charset.empty() ? "utf-8" : fs_charset.c_str();
+#else
+ return "utf-8";
+#endif
+}
+
+static inline void FixSeparators(std::string &s)
+{
+#ifdef WIN32
+ // For whatever reason GCC can't convert constexpr to value reference.
+ // This leads to link errors when passing separators directly.
+ auto from = PathTraitsFS::SEPARATOR;
+ auto to = PathTraitsUTF8::SEPARATOR;
+ std::replace(s.begin(), s.end(), from, to);
+#else
+ (void)s;
+#endif
}
std::string
@@ -81,8 +104,14 @@ PathToUTF8(const char *path_fs)
{
assert(path_fs != nullptr);
- if (fs_charset.empty())
- return std::string(path_fs);
+#ifdef HAVE_GLIB
+ if (fs_charset.empty()) {
+#endif
+ auto result = std::string(path_fs);
+ FixSeparators(result);
+ return result;
+#ifdef HAVE_GLIB
+ }
GIConv conv = g_iconv_open("utf-8", fs_charset.c_str());
if (conv == reinterpret_cast<GIConv>(-1))
@@ -103,9 +132,14 @@ PathToUTF8(const char *path_fs)
if (ret == static_cast<size_t>(-1) || in_left > 0)
return std::string();
- return std::string(path_utf8, sizeof(path_utf8) - out_left);
+ auto result_path = std::string(path_utf8, sizeof(path_utf8) - out_left);
+ FixSeparators(result_path);
+ return result_path;
+#endif
}
+#ifdef HAVE_GLIB
+
char *
PathFromUTF8(const char *path_utf8)
{
@@ -118,3 +152,5 @@ PathFromUTF8(const char *path_utf8)
fs_charset.c_str(), "utf-8",
nullptr, nullptr, nullptr);
}
+
+#endif
diff --git a/src/fs/Charset.hxx b/src/fs/Charset.hxx
index a89cb0459..0a71d7c58 100644
--- a/src/fs/Charset.hxx
+++ b/src/fs/Charset.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/CheckFile.cxx b/src/fs/CheckFile.cxx
new file mode 100644
index 000000000..a35443674
--- /dev/null
+++ b/src/fs/CheckFile.cxx
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2003-2014 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 "CheckFile.hxx"
+#include "Log.hxx"
+#include "config/ConfigError.hxx"
+#include "FileSystem.hxx"
+#include "Path.hxx"
+#include "AllocatedPath.hxx"
+#include "DirectoryReader.hxx"
+
+#include <errno.h>
+#include <sys/stat.h>
+
+void
+CheckDirectoryReadable(Path path_fs)
+{
+ struct stat st;
+ if (!StatFile(path_fs, st)) {
+ FormatErrno(config_domain,
+ "Failed to stat directory \"%s\"",
+ path_fs.c_str());
+ return;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ FormatError(config_domain,
+ "Not a directory: %s", path_fs.c_str());
+ return;
+ }
+
+#ifndef WIN32
+ const auto x = AllocatedPath::Build(path_fs, ".");
+ if (!StatFile(x, st) && errno == EACCES)
+ FormatError(config_domain,
+ "No permission to traverse (\"execute\") directory: %s",
+ path_fs.c_str());
+#endif
+
+ const DirectoryReader reader(path_fs);
+ if (reader.HasFailed() && errno == EACCES)
+ FormatError(config_domain,
+ "No permission to read directory: %s", path_fs.c_str());
+
+}
diff --git a/src/fs/CheckFile.hxx b/src/fs/CheckFile.hxx
new file mode 100644
index 000000000..00559647d
--- /dev/null
+++ b/src/fs/CheckFile.hxx
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2003-2014 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_CHECK_FILE_HXX
+#define MPD_FS_CHECK_FILE_HXX
+
+#include "check.h"
+
+class Path;
+
+/**
+ * Check whether the directory is readable and usable. Logs a warning
+ * if there is a problem.
+ */
+void
+CheckDirectoryReadable(Path path_fs);
+
+#endif
diff --git a/src/fs/Config.cxx b/src/fs/Config.cxx
index 63e64ef99..6aa23005c 100644
--- a/src/fs/Config.cxx
+++ b/src/fs/Config.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,24 +20,19 @@
#include "config.h"
#include "Config.hxx"
#include "Charset.hxx"
-#include "Domain.hxx"
-#include "ConfigGlobal.hxx"
-#include "Log.hxx"
-#include "Compiler.h"
-
-#include <glib.h>
-
-#include <assert.h>
-#include <string.h>
+#include "config/ConfigGlobal.hxx"
#ifdef WIN32
#include <windows.h> // for GetACP()
#include <stdio.h> // for sprintf()
+#elif defined(HAVE_GLIB)
+#include <glib.h>
#endif
void
ConfigureFS()
{
+#if defined(HAVE_GLIB) || defined(WIN32)
const char *charset = nullptr;
charset = config_get_string(CONF_FS_CHARSET, nullptr);
@@ -62,4 +57,5 @@ ConfigureFS()
if (charset != nullptr)
SetFSCharset(charset);
+#endif
}
diff --git a/src/fs/Config.hxx b/src/fs/Config.hxx
index 9d7035706..d4f1709f5 100644
--- a/src/fs/Config.hxx
+++ b/src/fs/Config.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/DirectoryReader.hxx b/src/fs/DirectoryReader.hxx
index c9d2c04b8..f77c0629f 100644
--- a/src/fs/DirectoryReader.hxx
+++ b/src/fs/DirectoryReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,7 @@
#define MPD_FS_DIRECTORY_READER_HXX
#include "check.h"
-#include "AllocatedPath.hxx"
+#include "Path.hxx"
#include <dirent.h>
@@ -78,9 +78,9 @@ public:
/**
* Extracts directory entry that was previously read by #ReadEntry.
*/
- AllocatedPath GetEntry() const {
+ Path GetEntry() const {
assert(HasEntry());
- return AllocatedPath::FromFS(ent->d_name);
+ return Path::FromFS(ent->d_name);
}
};
diff --git a/src/fs/Domain.cxx b/src/fs/Domain.cxx
index 0877bca4c..4f3129219 100644
--- a/src/fs/Domain.cxx
+++ b/src/fs/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/Domain.hxx b/src/fs/Domain.hxx
index b303570fc..1fd17b37f 100644
--- a/src/fs/Domain.hxx
+++ b/src/fs/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/FileSystem.cxx b/src/fs/FileSystem.cxx
index 4cd9f33b2..4e7c87415 100644
--- a/src/fs/FileSystem.cxx
+++ b/src/fs/FileSystem.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/FileSystem.hxx b/src/fs/FileSystem.hxx
index cb2f82d22..4dbb064cb 100644
--- a/src/fs/FileSystem.hxx
+++ b/src/fs/FileSystem.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,6 @@
#include <sys/stat.h>
#include <unistd.h>
-#include <assert.h>
#include <stdio.h>
class AllocatedPath;
@@ -37,39 +36,39 @@ namespace FOpenMode {
/**
* Open mode for reading text files.
*/
- constexpr PathTraits::const_pointer ReadText = "r";
+ constexpr PathTraitsFS::const_pointer ReadText = "r";
/**
* Open mode for reading binary files.
*/
- constexpr PathTraits::const_pointer ReadBinary = "rb";
+ constexpr PathTraitsFS::const_pointer ReadBinary = "rb";
/**
* Open mode for writing text files.
*/
- constexpr PathTraits::const_pointer WriteText = "w";
+ constexpr PathTraitsFS::const_pointer WriteText = "w";
/**
* Open mode for writing binary files.
*/
- constexpr PathTraits::const_pointer WriteBinary = "wb";
+ constexpr PathTraitsFS::const_pointer WriteBinary = "wb";
/**
* Open mode for appending text files.
*/
- constexpr PathTraits::const_pointer AppendText = "a";
+ constexpr PathTraitsFS::const_pointer AppendText = "a";
/**
* Open mode for appending binary files.
*/
- constexpr PathTraits::const_pointer AppendBinary = "ab";
+ constexpr PathTraitsFS::const_pointer AppendBinary = "ab";
}
/**
* Wrapper for fopen() that uses #Path names.
*/
static inline FILE *
-FOpen(Path file, PathTraits::const_pointer mode)
+FOpen(Path file, PathTraitsFS::const_pointer mode)
{
return fopen(file.c_str(), mode);
}
@@ -132,20 +131,28 @@ MakeFifo(Path path, mode_t mode)
return mkfifo(path.c_str(), mode) == 0;
}
-#endif
-
/**
* Wrapper for access() that uses #Path names.
*/
static inline bool
CheckAccess(Path path, int mode)
{
+ return access(path.c_str(), mode) == 0;
+}
+
+#endif
+
+/**
+ * Checks is specified path exists and accessible.
+ */
+static inline bool
+CheckAccess(Path path)
+{
#ifdef WIN32
- (void)path;
- (void)mode;
- return true;
+ struct stat buf;
+ return StatFile(path, buf);
#else
- return access(path.c_str(), mode) == 0;
+ return CheckAccess(path, F_OK);
#endif
}
diff --git a/src/fs/Limits.hxx b/src/fs/Limits.hxx
index 480b08851..432897a69 100644
--- a/src/fs/Limits.hxx
+++ b/src/fs/Limits.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/Path.cxx b/src/fs/Path.cxx
index 0ff0591fb..8288a4fec 100644
--- a/src/fs/Path.cxx
+++ b/src/fs/Path.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,25 +26,3 @@ Path::ToUTF8() const
{
return ::PathToUTF8(c_str());
}
-
-const char *
-Path::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;
-}
diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx
index 6ea954577..9e0fa5aeb 100644
--- a/src/fs/Path.hxx
+++ b/src/fs/Path.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,8 +29,6 @@
#include <assert.h>
#include <string.h>
-class Error;
-
/**
* A path name in the native file system character set.
*
@@ -38,9 +36,9 @@ class Error;
* instance lives, the string must not be invalidated.
*/
class Path {
- typedef PathTraits::value_type value_type;
- typedef PathTraits::pointer pointer;
- typedef PathTraits::const_pointer const_pointer;
+ typedef PathTraitsFS::value_type value_type;
+ typedef PathTraitsFS::pointer pointer;
+ typedef PathTraitsFS::const_pointer const_pointer;
const char *value;
@@ -137,11 +135,13 @@ public:
* nullptr on mismatch.
*/
gcc_pure
- const char *RelativeFS(const char *other_fs) const;
+ const char *RelativeFS(const char *other_fs) const {
+ return PathTraitsFS::Relative(value, other_fs);
+ }
gcc_pure
bool IsAbsolute() {
- return PathTraits::IsAbsoluteFS(c_str());
+ return PathTraitsFS::IsAbsolute(c_str());
}
};
diff --git a/src/fs/StandardDirectory.cxx b/src/fs/StandardDirectory.cxx
new file mode 100644
index 000000000..4f0958995
--- /dev/null
+++ b/src/fs/StandardDirectory.cxx
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2003-2014 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"
+
+// Use X Desktop guidelines where applicable
+#if !defined(__APPLE__) && !defined(WIN32)
+#define USE_XDG
+#endif
+
+#include "StandardDirectory.hxx"
+#include "FileSystem.hxx"
+
+#include <array>
+
+#ifdef WIN32
+#include <windows.h>
+#include <shlobj.h>
+#else
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+#endif
+
+#ifdef USE_XDG
+#include "util/CharUtil.hxx"
+#include "util/StringUtil.hxx"
+#include "TextFile.hxx"
+#include <string.h>
+#include <utility>
+#endif
+
+#ifndef WIN32
+class PasswdEntry
+{
+#if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
+ std::array<char, 16 * 1024> buf;
+ passwd pw;
+#endif
+
+ passwd *result;
+public:
+ PasswdEntry() : result(nullptr) { }
+
+ bool ReadByName(const char *name) {
+#ifdef HAVE_GETPWNAM_R
+ getpwnam_r(name, &pw, buf.data(), buf.size(), &result);
+#else
+ result = getpwnam(name);
+#endif
+ return result != nullptr;
+ }
+
+ bool ReadByUid(uid_t uid) {
+#ifdef HAVE_GETPWUID_R
+ getpwuid_r(uid, &pw, buf.data(), buf.size(), &result);
+#else
+ result = getpwuid(uid);
+#endif
+ return result != nullptr;
+ }
+
+ const passwd *operator->() {
+ assert(result != nullptr);
+ return result;
+ }
+};
+#endif
+
+static inline bool IsValidPathString(PathTraitsFS::const_pointer path)
+{
+ return path != nullptr && *path != '\0';
+}
+
+static inline bool IsValidDir(PathTraitsFS::const_pointer dir)
+{
+ return PathTraitsFS::IsAbsolute(dir) &&
+ DirectoryExists(Path::FromFS(dir));
+}
+
+static inline AllocatedPath SafePathFromFS(PathTraitsFS::const_pointer dir)
+{
+ if (IsValidPathString(dir) && IsValidDir(dir))
+ return AllocatedPath::FromFS(dir);
+ return AllocatedPath::Null();
+}
+
+#ifdef WIN32
+static AllocatedPath GetStandardDir(int folder_id)
+{
+ std::array<char, MAX_PATH> dir;
+ auto ret = SHGetFolderPath(nullptr, folder_id | CSIDL_FLAG_DONT_VERIFY,
+ nullptr, SHGFP_TYPE_CURRENT, dir.data());
+ if (FAILED(ret))
+ return AllocatedPath::Null();
+ return SafePathFromFS(dir.data());
+}
+#endif
+
+#ifdef USE_XDG
+
+static const char home_prefix[] = "$HOME/";
+
+static bool ParseConfigLine(const char *line, const char *dir_name,
+ AllocatedPath &result_dir)
+{
+ // strip leading white space
+ line = strchug_fast(line);
+
+ // check for end-of-line or comment
+ if (*line == '\0' || *line == '#')
+ return false;
+
+ // check if current setting is for requested dir
+ if (!StringStartsWith(line, dir_name))
+ return false;
+ line += strlen(dir_name);
+
+ // strip equals sign and spaces around it
+ line = strchug_fast(line);
+ if (*line != '=')
+ return false;
+ ++line;
+ line = strchug_fast(line);
+
+ // check if path is quoted
+ bool quoted = false;
+ if (*line == '"') {
+ ++line;
+ quoted = true;
+ }
+
+ // check if path is relative to $HOME
+ bool home_relative = false;
+ if (StringStartsWith(line, home_prefix)) {
+ line += strlen(home_prefix);
+ home_relative = true;
+ }
+
+
+ const char *line_end;
+ // find end of the string
+ if (quoted) {
+ line_end = strrchr(line, '"');
+ if (line_end == nullptr)
+ return true;
+ } else {
+ line_end = line + strlen(line);
+ while (line < line_end && IsWhitespaceNotNull(line_end[-1]))
+ --line_end;
+ }
+
+ // check for empty result
+ if (line == line_end)
+ return true;
+
+ // build the result path
+ std::string path(line, line_end);
+
+ auto result = AllocatedPath::Null();
+ if (home_relative) {
+ auto home = GetHomeDir();
+ if (home.IsNull())
+ return true;
+ result = AllocatedPath::Build(home, path.c_str());
+ } else {
+ result = AllocatedPath::FromFS(std::move(path));
+ }
+
+ if (IsValidDir(result.c_str())) {
+ result_dir = std::move(result);
+ return true;
+ }
+ return true;
+}
+
+static AllocatedPath GetUserDir(const char *name)
+{
+ auto result = AllocatedPath::Null();
+ auto config_dir = GetUserConfigDir();
+ if (config_dir.IsNull())
+ return result;
+ auto dirs_file = AllocatedPath::Build(config_dir, "user-dirs.dirs");
+ TextFile input(dirs_file);
+ if (input.HasFailed())
+ return result;
+ const char *line;
+ while ((line = input.ReadLine()) != nullptr)
+ if (ParseConfigLine(line, name, result))
+ return result;
+ return result;
+}
+
+#endif
+
+AllocatedPath GetUserConfigDir()
+{
+#if defined(WIN32)
+ return GetStandardDir(CSIDL_LOCAL_APPDATA);
+#elif defined(USE_XDG)
+ // Check for $XDG_CONFIG_HOME
+ auto config_home = getenv("XDG_CONFIG_HOME");
+ if (IsValidPathString(config_home) && IsValidDir(config_home))
+ return AllocatedPath::FromFS(config_home);
+
+ // Check for $HOME/.config
+ auto home = GetHomeDir();
+ if (!home.IsNull()) {
+ AllocatedPath fallback = AllocatedPath::Build(home, ".config");
+ if (IsValidDir(fallback.c_str()))
+ return fallback;
+ }
+
+ return AllocatedPath::Null();
+#else
+ return AllocatedPath::Null();
+#endif
+}
+
+AllocatedPath GetUserMusicDir()
+{
+#if defined(WIN32)
+ return GetStandardDir(CSIDL_MYMUSIC);
+#elif defined(USE_XDG)
+ return GetUserDir("XDG_MUSIC_DIR");
+#else
+ return AllocatedPath::Null();
+#endif
+}
+
+#ifdef WIN32
+
+AllocatedPath GetSystemConfigDir()
+{
+ return GetStandardDir(CSIDL_COMMON_APPDATA);
+}
+
+AllocatedPath GetAppBaseDir()
+{
+ std::array<char, MAX_PATH> app;
+ auto ret = GetModuleFileName(nullptr, app.data(), app.size());
+
+ // Check for error
+ if (ret == 0)
+ return AllocatedPath::Null();
+
+ // Check for truncation
+ if (ret == app.size() && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ return AllocatedPath::Null();
+
+ auto app_path = AllocatedPath::FromFS(app.data());
+ return app_path.GetDirectoryName().GetDirectoryName();
+}
+
+#else
+
+AllocatedPath GetHomeDir()
+{
+ auto home = getenv("HOME");
+ if (IsValidPathString(home) && IsValidDir(home))
+ return AllocatedPath::FromFS(home);
+ PasswdEntry pw;
+ if (pw.ReadByUid(getuid()))
+ return SafePathFromFS(pw->pw_dir);
+ return AllocatedPath::Null();
+}
+
+AllocatedPath GetHomeDir(const char *user_name)
+{
+ assert(user_name != nullptr);
+ PasswdEntry pw;
+ if (pw.ReadByName(user_name))
+ return SafePathFromFS(pw->pw_dir);
+ return AllocatedPath::Null();
+}
+
+#endif
diff --git a/src/fs/StandardDirectory.hxx b/src/fs/StandardDirectory.hxx
new file mode 100644
index 000000000..dca35b486
--- /dev/null
+++ b/src/fs/StandardDirectory.hxx
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2003-2014 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_STANDARD_DIRECTORY_HXX
+#define MPD_FS_STANDARD_DIRECTORY_HXX
+
+#include "check.h"
+#include "AllocatedPath.hxx"
+
+/**
+ * Obtains configuration directory for the current user.
+ */
+AllocatedPath GetUserConfigDir();
+
+/**
+ * Obtains music directory for the current user.
+ */
+AllocatedPath GetUserMusicDir();
+
+#ifdef WIN32
+
+/**
+ * Obtains system configuration directory.
+ */
+AllocatedPath GetSystemConfigDir();
+
+/**
+ * Obtains application application base directory.
+ * Application base directory is a directory that contains 'bin' folder
+ * for current executable.
+ */
+AllocatedPath GetAppBaseDir();
+
+#else
+
+/**
+ * Obtains home directory for the current user.
+ */
+AllocatedPath GetHomeDir();
+
+/**
+ * Obtains home directory for the specified user.
+ */
+AllocatedPath GetHomeDir(const char *user_name);
+
+#endif
+
+#endif
diff --git a/src/fs/TextFile.cxx b/src/fs/TextFile.cxx
new file mode 100644
index 000000000..b1a92b9cc
--- /dev/null
+++ b/src/fs/TextFile.cxx
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2003-2014 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 "TextFile.hxx"
+#include "util/Alloc.hxx"
+#include "fs/Path.hxx"
+#include "fs/FileSystem.hxx"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+TextFile::TextFile(Path path_fs)
+ :file(FOpen(path_fs, FOpenMode::ReadText)),
+ buffer((char *)xalloc(step)), capacity(step), length(0) {}
+
+TextFile::~TextFile()
+{
+ free(buffer);
+
+ if (file != nullptr)
+ fclose(file);
+}
+
+char *
+TextFile::ReadLine()
+{
+ assert(file != nullptr);
+
+ while (true) {
+ if (length >= capacity) {
+ if (capacity >= max_length)
+ /* too large already - bail out */
+ return nullptr;
+
+ capacity <<= 1;
+ char *new_buffer = (char *)realloc(buffer, capacity);
+ if (new_buffer == nullptr)
+ /* out of memory - bail out */
+ return nullptr;
+ }
+
+ char *p = fgets(buffer + length, capacity - length, file);
+ if (p == nullptr) {
+ if (length == 0 || ferror(file))
+ return nullptr;
+ break;
+ }
+
+ length += strlen(buffer + length);
+ if (buffer[length - 1] == '\n')
+ break;
+ }
+
+ /* remove the newline characters */
+ if (buffer[length - 1] == '\n')
+ --length;
+ if (buffer[length - 1] == '\r')
+ --length;
+
+ buffer[length] = 0;
+ length = 0;
+ return buffer;
+}
diff --git a/src/fs/TextFile.hxx b/src/fs/TextFile.hxx
new file mode 100644
index 000000000..e3a712a88
--- /dev/null
+++ b/src/fs/TextFile.hxx
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2003-2014 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_TEXT_FILE_HXX
+#define MPD_TEXT_FILE_HXX
+
+#include "Compiler.h"
+
+#include <stdio.h>
+#include <stddef.h>
+
+class Path;
+
+class TextFile {
+ static constexpr size_t max_length = 512 * 1024;
+ static constexpr size_t step = 1024;
+
+ FILE *const file;
+
+ char *buffer;
+ size_t capacity, length;
+
+public:
+ TextFile(Path path_fs);
+
+ TextFile(const TextFile &other) = delete;
+
+ ~TextFile();
+
+ bool HasFailed() const {
+ return gcc_unlikely(file == nullptr);
+ }
+
+ /**
+ * Reads a line from the input file, and strips trailing
+ * space. There is a reasonable maximum line length, only to
+ * prevent denial of service.
+ *
+ * @param file the source file, opened in text mode
+ * @param buffer an allocator for the buffer
+ * @return a pointer to the line, or nullptr on end-of-file or error
+ */
+ char *ReadLine();
+};
+
+#endif
diff --git a/src/fs/Traits.cxx b/src/fs/Traits.cxx
index 2c3ce075b..d62987087 100644
--- a/src/fs/Traits.cxx
+++ b/src/fs/Traits.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,24 +22,136 @@
#include <string.h>
-const char *
-PathTraits::GetBaseUTF8(const char *p)
+template<typename Traits>
+typename Traits::string
+BuildPathImpl(typename Traits::const_pointer a, size_t a_size,
+ typename Traits::const_pointer b, size_t b_size)
+{
+ assert(a != nullptr);
+ assert(b != nullptr);
+
+ if (a_size == 0)
+ return typename Traits::string(b, b_size);
+ if (b_size == 0)
+ return typename Traits::string(a, a_size);
+
+ typename Traits::string result(a, a_size);
+
+ if (!Traits::IsSeparator(a[a_size - 1]))
+ result.push_back(Traits::SEPARATOR);
+
+ if (Traits::IsSeparator(b[0]))
+ result.append(b + 1, b_size - 1);
+ else
+ result.append(b, b_size);
+
+ return result;
+}
+
+template<typename Traits>
+typename Traits::const_pointer
+GetBasePathImpl(typename Traits::const_pointer p)
{
assert(p != nullptr);
- const char *slash = strrchr(p, SEPARATOR_UTF8);
- return slash != nullptr
- ? slash + 1
+ typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
+ return sep != nullptr
+ ? sep + 1
: p;
}
-std::string
-PathTraits::GetParentUTF8(const char *p)
+template<typename Traits>
+typename Traits::string
+GetParentPathImpl(typename Traits::const_pointer p)
{
assert(p != nullptr);
- const char *slash = strrchr(p, SEPARATOR_UTF8);
- return slash != nullptr
- ? std::string(p, slash)
- : std::string(".");
+ typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
+ if (sep == nullptr)
+ return typename Traits::string(".");
+ if (sep == p)
+ return typename Traits::string(p, p + 1);
+#ifdef WIN32
+ if (Traits::IsDrive(p) && sep == p + 2)
+ return typename Traits::string(p, p + 3);
+#endif
+ return typename Traits::string(p, sep);
+}
+
+template<typename Traits>
+typename Traits::const_pointer
+RelativePathImpl(typename Traits::const_pointer base,
+ typename Traits::const_pointer other)
+{
+ assert(base != nullptr);
+ assert(other != nullptr);
+
+ const auto base_length = Traits::GetLength(base);
+ if (memcmp(base, other, base_length * sizeof(*base)) != 0)
+ /* mismatch */
+ return nullptr;
+
+ other += base_length;
+ if (other != 0) {
+ if (!Traits::IsSeparator(*other))
+ /* mismatch */
+ return nullptr;
+
+ /* skip remaining path separators */
+ do {
+ ++other;
+ } while (Traits::IsSeparator(*other));
+ }
+
+ return other;
+}
+
+PathTraitsFS::string
+PathTraitsFS::Build(PathTraitsFS::const_pointer a, size_t a_size,
+ PathTraitsFS::const_pointer b, size_t b_size)
+{
+ return BuildPathImpl<PathTraitsFS>(a, a_size, b, b_size);
+}
+
+PathTraitsFS::const_pointer
+PathTraitsFS::GetBase(PathTraitsFS::const_pointer p)
+{
+ return GetBasePathImpl<PathTraitsFS>(p);
+}
+
+PathTraitsFS::string
+PathTraitsFS::GetParent(PathTraitsFS::const_pointer p)
+{
+ return GetParentPathImpl<PathTraitsFS>(p);
+}
+
+PathTraitsFS::const_pointer
+PathTraitsFS::Relative(const_pointer base, const_pointer other)
+{
+ return RelativePathImpl<PathTraitsFS>(base, other);
+}
+
+PathTraitsUTF8::string
+PathTraitsUTF8::Build(PathTraitsUTF8::const_pointer a, size_t a_size,
+ PathTraitsUTF8::const_pointer b, size_t b_size)
+{
+ return BuildPathImpl<PathTraitsUTF8>(a, a_size, b, b_size);
+}
+
+PathTraitsUTF8::const_pointer
+PathTraitsUTF8::GetBase(PathTraitsUTF8::const_pointer p)
+{
+ return GetBasePathImpl<PathTraitsUTF8>(p);
+}
+
+PathTraitsUTF8::string
+PathTraitsUTF8::GetParent(PathTraitsUTF8::const_pointer p)
+{
+ return GetParentPathImpl<PathTraitsUTF8>(p);
+}
+
+PathTraitsUTF8::const_pointer
+PathTraitsUTF8::Relative(const_pointer base, const_pointer other)
+{
+ return RelativePathImpl<PathTraitsUTF8>(base, other);
}
diff --git a/src/fs/Traits.hxx b/src/fs/Traits.hxx
index 244ab8b5c..88715c3e8 100644
--- a/src/fs/Traits.hxx
+++ b/src/fs/Traits.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,67 +24,153 @@
#include "Compiler.h"
#ifdef WIN32
-#include <glib.h>
+#include "util/CharUtil.hxx"
#endif
#include <string>
+#include <string.h>
#include <assert.h>
-class Error;
-
/**
- * This class describes the nature of a filesystem path.
+ * This class describes the nature of a native filesystem path.
*/
-struct PathTraits {
+struct PathTraitsFS {
+ typedef std::string string;
typedef char value_type;
typedef char *pointer;
typedef const char *const_pointer;
#ifdef WIN32
- static constexpr value_type SEPARATOR_FS = '\\';
- static constexpr char SEPARATOR_UTF8 = '/';
+ static constexpr value_type SEPARATOR = '\\';
#else
- static constexpr value_type SEPARATOR_FS = '/';
- static constexpr char SEPARATOR_UTF8 = '/';
+ static constexpr value_type SEPARATOR = '/';
#endif
- static constexpr bool IsSeparatorFS(value_type ch) {
+ static constexpr bool IsSeparator(value_type ch) {
return
#ifdef WIN32
ch == '/' ||
#endif
- ch == SEPARATOR_FS;
+ ch == SEPARATOR;
}
- static constexpr bool IsSeparatorUTF8(char ch) {
- return
+ gcc_pure gcc_nonnull_all
+ static const_pointer FindLastSeparator(const_pointer p) {
+ assert(p != nullptr);
#ifdef WIN32
- ch == '/' ||
+ const_pointer pos = p + GetLength(p);
+ while (p != pos && !IsSeparator(*pos))
+ --pos;
+ return IsSeparator(*pos) ? pos : nullptr;
+#else
+ return strrchr(p, SEPARATOR);
#endif
- ch == SEPARATOR_UTF8;
}
- gcc_pure
- static bool IsAbsoluteFS(const_pointer p) {
- assert(p != nullptr);
+#ifdef WIN32
+ gcc_pure gcc_nonnull_all
+ static constexpr bool IsDrive(const_pointer p) {
+ return IsAlphaASCII(p[0]) && p[1] == ':';
+ }
+#endif
+ gcc_pure gcc_nonnull_all
+ static bool IsAbsolute(const_pointer p) {
+ assert(p != nullptr);
#ifdef WIN32
- return g_path_is_absolute(p);
-#else
- return IsSeparatorFS(*p);
+ if (IsDrive(p) && IsSeparator(p[2]))
+ return true;
#endif
+ return IsSeparator(*p);
}
- gcc_pure
- static bool IsAbsoluteUTF8(const char *p) {
+ gcc_pure gcc_nonnull_all
+ static size_t GetLength(const_pointer p) {
+ return strlen(p);
+ }
+
+ /**
+ * Determine the "base" file name of the given native path.
+ * The return value points inside the given string.
+ */
+ gcc_pure gcc_nonnull_all
+ static const_pointer GetBase(const_pointer p);
+
+ /**
+ * Determine the "parent" file name of the given native path.
+ * As a special case, returns the string "." if there is no
+ * separator in the given input string.
+ */
+ gcc_pure gcc_nonnull_all
+ static string GetParent(const_pointer p);
+
+ /**
+ * 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 gcc_nonnull_all
+ static const_pointer Relative(const_pointer base, const_pointer other);
+
+ /**
+ * Constructs the path from the given components.
+ * If either of the components is empty string,
+ * remaining component is returned unchanged.
+ * If both components are empty strings, empty string is returned.
+ */
+ gcc_pure gcc_nonnull_all
+ static string Build(const_pointer a, size_t a_size,
+ const_pointer b, size_t b_size);
+
+ gcc_pure gcc_nonnull_all
+ static string Build(const_pointer a, const_pointer b) {
+ return Build(a, GetLength(a), b, GetLength(b));
+ }
+};
+
+/**
+ * This class describes the nature of a MPD internal filesystem path.
+ */
+struct PathTraitsUTF8 {
+ typedef std::string string;
+ typedef char value_type;
+ typedef char *pointer;
+ typedef const char *const_pointer;
+
+ static constexpr value_type SEPARATOR = '/';
+
+ static constexpr bool IsSeparator(value_type ch) {
+ return ch == SEPARATOR;
+ }
+
+ gcc_pure gcc_nonnull_all
+ static const_pointer FindLastSeparator(const_pointer p) {
assert(p != nullptr);
+ return strrchr(p, SEPARATOR);
+ }
#ifdef WIN32
- return g_path_is_absolute(p);
-#else
- return IsSeparatorUTF8(*p);
+ gcc_pure gcc_nonnull_all
+ static constexpr bool IsDrive(const_pointer p) {
+ return IsAlphaASCII(p[0]) && p[1] == ':';
+ }
+#endif
+
+ gcc_pure gcc_nonnull_all
+ static bool IsAbsolute(const_pointer p) {
+ assert(p != nullptr);
+#ifdef WIN32
+ if (IsDrive(p) && IsSeparator(p[2]))
+ return true;
#endif
+ return IsSeparator(*p);
+ }
+
+ gcc_pure gcc_nonnull_all
+ static size_t GetLength(const_pointer p) {
+ return strlen(p);
}
/**
@@ -92,7 +178,7 @@ struct PathTraits {
* The return value points inside the given string.
*/
gcc_pure gcc_nonnull_all
- static const char *GetBaseUTF8(const char *p);
+ static const_pointer GetBase(const_pointer p);
/**
* Determine the "parent" file name of the given UTF-8 path.
@@ -100,7 +186,31 @@ struct PathTraits {
* separator in the given input string.
*/
gcc_pure gcc_nonnull_all
- static std::string GetParentUTF8(const char *p);
+ static string GetParent(const_pointer p);
+
+ /**
+ * 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 gcc_nonnull_all
+ static const_pointer Relative(const_pointer base, const_pointer other);
+
+ /**
+ * Constructs the path from the given components.
+ * If either of the components is empty string,
+ * remaining component is returned unchanged.
+ * If both components are empty strings, empty string is returned.
+ */
+ gcc_pure gcc_nonnull_all
+ static string Build(const_pointer a, size_t a_size,
+ const_pointer b, size_t b_size);
+
+ gcc_pure gcc_nonnull_all
+ static string Build(const_pointer a, const_pointer b) {
+ return Build(a, GetLength(a), b, GetLength(b));
+ }
};
#endif