aboutsummaryrefslogtreecommitdiffstats
path: root/src/fs
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs')
-rw-r--r--src/fs/AllocatedPath.cxx51
-rw-r--r--src/fs/AllocatedPath.hxx31
-rw-r--r--src/fs/Charset.cxx163
-rw-r--r--src/fs/Charset.hxx28
-rw-r--r--src/fs/CheckFile.cxx36
-rw-r--r--src/fs/CheckFile.hxx2
-rw-r--r--src/fs/Config.cxx38
-rw-r--r--src/fs/Config.hxx9
-rw-r--r--src/fs/DirectoryReader.hxx87
-rw-r--r--src/fs/Domain.cxx2
-rw-r--r--src/fs/Domain.hxx2
-rw-r--r--src/fs/FileInfo.hxx156
-rw-r--r--src/fs/FileSystem.cxx2
-rw-r--r--src/fs/FileSystem.hxx94
-rw-r--r--src/fs/Limits.hxx2
-rw-r--r--src/fs/NarrowPath.hxx69
-rw-r--r--src/fs/Path.cxx15
-rw-r--r--src/fs/Path.hxx43
-rw-r--r--src/fs/Path2.cxx28
-rw-r--r--src/fs/StandardDirectory.cxx6
-rw-r--r--src/fs/StandardDirectory.hxx2
-rw-r--r--src/fs/Traits.cxx6
-rw-r--r--src/fs/Traits.hxx41
-rw-r--r--src/fs/io/AutoGunzipReader.cxx2
-rw-r--r--src/fs/io/AutoGunzipReader.hxx2
-rw-r--r--src/fs/io/BufferedOutputStream.cxx7
-rw-r--r--src/fs/io/BufferedOutputStream.hxx20
-rw-r--r--src/fs/io/BufferedReader.cxx7
-rw-r--r--src/fs/io/BufferedReader.hxx11
-rw-r--r--src/fs/io/FileOutputStream.cxx187
-rw-r--r--src/fs/io/FileOutputStream.hxx115
-rw-r--r--src/fs/io/FileReader.cxx78
-rw-r--r--src/fs/io/FileReader.hxx35
-rw-r--r--src/fs/io/GunzipReader.cxx2
-rw-r--r--src/fs/io/GunzipReader.hxx2
-rw-r--r--src/fs/io/GzipOutputStream.cxx2
-rw-r--r--src/fs/io/GzipOutputStream.hxx2
-rw-r--r--src/fs/io/OutputStream.hxx2
-rw-r--r--src/fs/io/PeekReader.cxx2
-rw-r--r--src/fs/io/PeekReader.hxx2
-rw-r--r--src/fs/io/Reader.hxx2
-rw-r--r--src/fs/io/StdioOutputStream.hxx2
-rw-r--r--src/fs/io/TextFile.cxx8
-rw-r--r--src/fs/io/TextFile.hxx5
44 files changed, 1070 insertions, 338 deletions
diff --git a/src/fs/AllocatedPath.cxx b/src/fs/AllocatedPath.cxx
index ceaad73ea..8b03ed2f1 100644
--- a/src/fs/AllocatedPath.cxx
+++ b/src/fs/AllocatedPath.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,33 +24,14 @@
#include "util/Error.hxx"
#include "Compiler.h"
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
-#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::FromUTF8(const char *path_utf8)
{
-#ifdef HAVE_GLIB
- char *path = ::PathFromUTF8(path_utf8);
- if (path == nullptr)
- return AllocatedPath::Null();
-
- return AllocatedPath(Donate(), path);
+#if defined(HAVE_FS_CHARSET) || defined(WIN32)
+ return AllocatedPath(::PathFromUTF8(path_utf8));
#else
return FromFS(path_utf8);
#endif
@@ -80,38 +61,16 @@ 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 (!PathTraitsFS::IsSeparator(*other_fs))
- /* mismatch */
- return nullptr;
-
- /* skip remaining path separators */
- do {
- ++other_fs;
- } while (PathTraitsFS::IsSeparator(*other_fs));
- }
-
- return other_fs;
-}
-
void
AllocatedPath::ChopSeparators()
{
size_t l = length();
- const char *p = data();
+ const auto *p = data();
while (l >= 2 && PathTraitsFS::IsSeparator(p[l - 1])) {
--l;
-#if GCC_CHECK_VERSION(4,7) && !defined(__clang__)
+#if GCC_CHECK_VERSION(4,7)
value.pop_back();
#else
value.erase(value.end() - 1, value.end());
diff --git a/src/fs/AllocatedPath.hxx b/src/fs/AllocatedPath.hxx
index c345470c8..e733c00a9 100644
--- a/src/fs/AllocatedPath.hxx
+++ b/src/fs/AllocatedPath.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "Traits.hxx"
#include "Path.hxx"
+#include <cstddef>
#include <utility>
#include <string>
@@ -44,13 +45,7 @@ class AllocatedPath {
string value;
- struct Donate {};
-
- /**
- * Donate the allocated pointer to a new #AllocatedPath object.
- */
- AllocatedPath(Donate, pointer _value);
-
+ AllocatedPath(std::nullptr_t):value() {}
AllocatedPath(const_pointer _value):value(_value) {}
AllocatedPath(string &&_value):value(std::move(_value)) {}
@@ -82,7 +77,7 @@ public:
*/
gcc_const
static AllocatedPath Null() {
- return AllocatedPath("");
+ return AllocatedPath(nullptr);
}
gcc_pure
@@ -169,11 +164,21 @@ public:
return *this;
}
+ gcc_pure
+ bool operator==(const AllocatedPath &other) const {
+ return value == other.value;
+ }
+
+ gcc_pure
+ bool operator!=(const AllocatedPath &other) const {
+ return value != other.value;
+ }
+
/**
* Allows the caller to "steal" the internal value by
* providing a rvalue reference to the std::string attribute.
*/
- std::string &&Steal() {
+ string &&Steal() {
return std::move(value);
}
@@ -244,7 +249,9 @@ public:
* nullptr on mismatch.
*/
gcc_pure
- const char *RelativeFS(const char *other_fs) const;
+ const_pointer Relative(Path other_fs) const {
+ return PathTraitsFS::Relative(c_str(), other_fs.c_str());
+ }
/**
* Chop trailing directory separators.
@@ -252,7 +259,7 @@ public:
void ChopSeparators();
gcc_pure
- bool IsAbsolute() {
+ bool IsAbsolute() const {
return PathTraitsFS::IsAbsolute(c_str());
}
};
diff --git a/src/fs/Charset.cxx b/src/fs/Charset.cxx
index c634c9340..b25615d42 100644
--- a/src/fs/Charset.cxx
+++ b/src/fs/Charset.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,12 +21,12 @@
#include "Charset.hxx"
#include "Domain.hxx"
#include "Limits.hxx"
-#include "system/FatalError.hxx"
#include "Log.hxx"
-#include "Traits.hxx"
+#include "lib/icu/Converter.hxx"
+#include "util/Error.hxx"
-#ifdef HAVE_GLIB
-#include <glib.h>
+#ifdef WIN32
+#include <windows.h>
#endif
#include <algorithm>
@@ -34,130 +34,133 @@
#include <assert.h>
#include <string.h>
-#ifdef HAVE_GLIB
-
-/**
- * Maximal number of bytes required to represent path name in UTF-8
- * (including nul-terminator).
- * This value is a rought estimate of upper bound.
- * It's based on path name limit in bytes (MPD_PATH_MAX)
- * and assumption that some weird encoding could represent some UTF-8 4 byte
- * sequences with single byte.
- */
-static constexpr size_t MPD_PATH_MAX_UTF8 = (MPD_PATH_MAX - 1) * 4 + 1;
+#ifdef HAVE_FS_CHARSET
static std::string fs_charset;
-gcc_pure
-static bool
-IsSupportedCharset(const char *charset)
-{
- /* convert a space to check if the charset is valid */
- char *test = g_convert(" ", 1, charset, "UTF-8", nullptr, nullptr, nullptr);
- if (test == nullptr)
- return false;
+static IcuConverter *fs_converter;
- g_free(test);
- return true;
-}
-
-void
-SetFSCharset(const char *charset)
+bool
+SetFSCharset(const char *charset, Error &error)
{
assert(charset != nullptr);
+ assert(fs_converter == nullptr);
- if (!IsSupportedCharset(charset))
- FormatFatalError("invalid filesystem charset: %s", charset);
-
- fs_charset = charset;
+ fs_converter = IcuConverter::Create(charset, error);
+ if (fs_converter == nullptr)
+ return false;
FormatDebug(path_domain,
"SetFSCharset: fs charset is: %s", fs_charset.c_str());
+ return true;
}
#endif
+void
+DeinitFSCharset()
+{
+#ifdef HAVE_ICU_CONVERTER
+ delete fs_converter;
+ fs_converter = nullptr;
+#endif
+}
+
const char *
GetFSCharset()
{
-#ifdef HAVE_GLIB
+#ifdef HAVE_FS_CHARSET
return fs_charset.empty() ? "UTF-8" : fs_charset.c_str();
#else
return "UTF-8";
#endif
}
-static inline void FixSeparators(std::string &s)
+static inline PathTraitsUTF8::string &&
+FixSeparators(PathTraitsUTF8::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
+ decltype(to) from = PathTraitsFS::SEPARATOR;
+
+ if (from != to)
+ /* convert backslash to slash on WIN32 */
+ std::replace(s.begin(), s.end(), from, to);
+
+ return std::move(s);
}
-std::string
-PathToUTF8(const char *path_fs)
+PathTraitsUTF8::string
+PathToUTF8(PathTraitsFS::const_pointer path_fs)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_fs != nullptr);
#endif
-#ifdef HAVE_GLIB
- if (fs_charset.empty()) {
-#endif
- auto result = std::string(path_fs);
- FixSeparators(result);
- return result;
-#ifdef HAVE_GLIB
+#ifdef WIN32
+ int length = WideCharToMultiByte(CP_UTF8, 0, path_fs, -1, nullptr, 0,
+ nullptr, nullptr);
+ if (length <= 0)
+ return PathTraitsUTF8::string();
+
+ char *buffer = new char[length];
+ length = WideCharToMultiByte(CP_UTF8, 0, path_fs, -1, buffer, length,
+ nullptr, nullptr);
+ if (length <= 0) {
+ delete[] buffer;
+ return PathTraitsUTF8::string();
}
- GIConv conv = g_iconv_open("utf-8", fs_charset.c_str());
- if (conv == reinterpret_cast<GIConv>(-1))
- return std::string();
-
- // g_iconv() does not need nul-terminator,
- // std::string could be created without it too.
- char path_utf8[MPD_PATH_MAX_UTF8 - 1];
- char *in = const_cast<char *>(path_fs);
- char *out = path_utf8;
- size_t in_left = strlen(path_fs);
- size_t out_left = sizeof(path_utf8);
-
- size_t ret = g_iconv(conv, &in, &in_left, &out, &out_left);
-
- g_iconv_close(conv);
-
- if (ret == static_cast<size_t>(-1) || in_left > 0)
- return std::string();
+ PathTraitsUTF8::string result(buffer);
+ delete[] buffer;
+ return FixSeparators(std::move(result));
+#else
+#ifdef HAVE_FS_CHARSET
+ if (fs_converter == nullptr)
+#endif
+ return FixSeparators(path_fs);
+#ifdef HAVE_FS_CHARSET
- auto result_path = std::string(path_utf8, sizeof(path_utf8) - out_left);
- FixSeparators(result_path);
- return result_path;
+ return FixSeparators(fs_converter->ToUTF8(path_fs));
+#endif
#endif
}
-#ifdef HAVE_GLIB
+#if defined(HAVE_FS_CHARSET) || defined(WIN32)
-char *
-PathFromUTF8(const char *path_utf8)
+PathTraitsFS::string
+PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_utf8 != nullptr);
#endif
- if (fs_charset.empty())
- return g_strdup(path_utf8);
+#ifdef WIN32
+ int length = MultiByteToWideChar(CP_UTF8, 0, path_utf8, -1,
+ nullptr, 0);
+ if (length <= 0)
+ return PathTraitsFS::string();
+
+ wchar_t *buffer = new wchar_t[length];
+ length = MultiByteToWideChar(CP_UTF8, 0, path_utf8, -1,
+ buffer, length);
+ if (length <= 0) {
+ delete[] buffer;
+ return PathTraitsFS::string();
+ }
+
+ PathTraitsFS::string result(buffer);
+ delete[] buffer;
+ return std::move(result);
+#else
+ if (fs_converter == nullptr)
+ return path_utf8;
- return g_convert(path_utf8, -1,
- fs_charset.c_str(), "utf-8",
- nullptr, nullptr, nullptr);
+ return fs_converter->FromUTF8(path_utf8);
+#endif
}
#endif
diff --git a/src/fs/Charset.hxx b/src/fs/Charset.hxx
index 0a71d7c58..49ad07820 100644
--- a/src/fs/Charset.hxx
+++ b/src/fs/Charset.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,13 @@
#include "check.h"
#include "Compiler.h"
+#include "Traits.hxx"
-#include <string>
+#if defined(HAVE_ICU) || defined(HAVE_GLIB)
+#define HAVE_FS_CHARSET
+#endif
+
+class Error;
/**
* Gets file system character set name.
@@ -32,19 +37,26 @@ gcc_const
const char *
GetFSCharset();
+bool
+SetFSCharset(const char *charset, Error &error);
+
void
-SetFSCharset(const char *charset);
+DeinitFSCharset();
/**
* Convert the path to UTF-8.
* Returns empty string on error.
*/
gcc_pure gcc_nonnull_all
-std::string
-PathToUTF8(const char *path_fs);
+PathTraitsUTF8::string
+PathToUTF8(PathTraitsFS::const_pointer path_fs);
-gcc_malloc gcc_nonnull_all
-char *
-PathFromUTF8(const char *path_utf8);
+/**
+ * Convert the path from UTF-8.
+ * Returns empty string on error.
+ */
+gcc_pure gcc_nonnull_all
+PathTraitsFS::string
+PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8);
#endif
diff --git a/src/fs/CheckFile.cxx b/src/fs/CheckFile.cxx
index a35443674..e900fe9af 100644
--- a/src/fs/CheckFile.cxx
+++ b/src/fs/CheckFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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 @@
#include "CheckFile.hxx"
#include "Log.hxx"
#include "config/ConfigError.hxx"
-#include "FileSystem.hxx"
+#include "FileInfo.hxx"
#include "Path.hxx"
#include "AllocatedPath.hxx"
#include "DirectoryReader.hxx"
@@ -32,31 +32,37 @@
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());
+ Error error;
+
+ FileInfo fi;
+ if (!GetFileInfo(path_fs, fi, error)) {
+ LogError(error);
return;
}
- if (!S_ISDIR(st.st_mode)) {
+ if (!fi.IsDirectory()) {
+ const auto path_utf8 = path_fs.ToUTF8();
FormatError(config_domain,
- "Not a directory: %s", path_fs.c_str());
+ "Not a directory: %s", path_utf8.c_str());
return;
}
#ifndef WIN32
- const auto x = AllocatedPath::Build(path_fs, ".");
- if (!StatFile(x, st) && errno == EACCES)
+ const auto x = AllocatedPath::Build(path_fs,
+ PathTraitsFS::CURRENT_DIRECTORY);
+ if (!GetFileInfo(x, fi) && errno == EACCES) {
+ const auto path_utf8 = path_fs.ToUTF8();
FormatError(config_domain,
"No permission to traverse (\"execute\") directory: %s",
- path_fs.c_str());
+ path_utf8.c_str());
+ }
#endif
const DirectoryReader reader(path_fs);
- if (reader.HasFailed() && errno == EACCES)
+ if (reader.HasFailed() && errno == EACCES) {
+ const auto path_utf8 = path_fs.ToUTF8();
FormatError(config_domain,
- "No permission to read directory: %s", path_fs.c_str());
-
+ "No permission to read directory: %s",
+ path_utf8.c_str());
+ }
}
diff --git a/src/fs/CheckFile.hxx b/src/fs/CheckFile.hxx
index 00559647d..52fe45f0a 100644
--- a/src/fs/CheckFile.hxx
+++ b/src/fs/CheckFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/Config.cxx b/src/fs/Config.cxx
index 6aa23005c..623736c54 100644
--- a/src/fs/Config.cxx
+++ b/src/fs/Config.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,21 +29,15 @@
#include <glib.h>
#endif
-void
-ConfigureFS()
+bool
+ConfigureFS(Error &error)
{
-#if defined(HAVE_GLIB) || defined(WIN32)
+#ifdef HAVE_FS_CHARSET
const char *charset = nullptr;
- charset = config_get_string(CONF_FS_CHARSET, nullptr);
+ charset = config_get_string(ConfigOption::FS_CHARSET, nullptr);
if (charset == nullptr) {
-#ifndef WIN32
- const gchar **encodings;
- g_get_filename_charsets(&encodings);
-
- if (encodings[0] != nullptr && *encodings[0] != '\0')
- charset = encodings[0];
-#else
+#ifdef WIN32
/* Glib claims that file system encoding is always utf-8
* on native Win32 (i.e. not Cygwin).
* However this is true only if <gstdio.h> helpers are used.
@@ -52,10 +46,26 @@ ConfigureFS()
static char win_charset[13];
sprintf(win_charset, "cp%u", GetACP());
charset = win_charset;
+#elif defined(HAVE_GLIB)
+ const gchar **encodings;
+ g_get_filename_charsets(&encodings);
+
+ if (encodings[0] != nullptr && *encodings[0] != '\0')
+ charset = encodings[0];
#endif
}
- if (charset != nullptr)
- SetFSCharset(charset);
+ return charset == nullptr || SetFSCharset(charset, error);
+#else
+ (void)error;
+ return true;
+#endif
+}
+
+void
+DeinitFS()
+{
+#ifdef HAVE_FS_CHARSET
+ DeinitFSCharset();
#endif
}
diff --git a/src/fs/Config.hxx b/src/fs/Config.hxx
index d4f1709f5..1db710551 100644
--- a/src/fs/Config.hxx
+++ b/src/fs/Config.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,10 +22,15 @@
#include "check.h"
+class Error;
+
/**
* Performs global one-time initialization of this class.
*/
+bool
+ConfigureFS(Error &error);
+
void
-ConfigureFS();
+DeinitFS();
#endif
diff --git a/src/fs/DirectoryReader.hxx b/src/fs/DirectoryReader.hxx
index f77c0629f..ce27d2b9b 100644
--- a/src/fs/DirectoryReader.hxx
+++ b/src/fs/DirectoryReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,89 @@
#include "check.h"
#include "Path.hxx"
+#ifdef WIN32
+
+#include <windows.h>
+#include <tchar.h>
+
+/**
+ * Reader for directory entries.
+ */
+class DirectoryReader {
+ const HANDLE handle;
+ WIN32_FIND_DATA data;
+ bool first;
+
+ class MakeWildcardPath {
+ PathTraitsFS::pointer path;
+
+ public:
+ MakeWildcardPath(PathTraitsFS::const_pointer _path) {
+ auto l = _tcslen(_path);
+ path = new PathTraitsFS::value_type[l + 3];
+ _tcscpy(path, _path);
+ path[l] = _T('\\');
+ path[l + 1] = _T('*');
+ path[l + 2] = 0;
+ }
+
+ ~MakeWildcardPath() {
+ delete[] path;
+ }
+
+ operator PathTraitsFS::const_pointer() const {
+ return path;
+ }
+ };
+
+public:
+ /**
+ * Creates new directory reader for the specified #dir.
+ */
+ explicit DirectoryReader(Path dir)
+ :handle(FindFirstFile(MakeWildcardPath(dir.c_str()), &data)),
+ first(true) {}
+
+ DirectoryReader(const DirectoryReader &other) = delete;
+ DirectoryReader &operator=(const DirectoryReader &other) = delete;
+
+ /**
+ * Destroys this instance.
+ */
+ ~DirectoryReader() {
+ if (!HasFailed())
+ FindClose(handle);
+ }
+
+ /**
+ * Checks if directory failed to open.
+ */
+ bool HasFailed() const {
+ return handle == INVALID_HANDLE_VALUE;
+ }
+
+ /**
+ * Reads next directory entry.
+ */
+ bool ReadEntry() {
+ if (first) {
+ first = false;
+ return true;
+ }
+
+ return FindNextFile(handle, &data) != 0;
+ }
+
+ /**
+ * Extracts directory entry that was previously read by #ReadEntry.
+ */
+ Path GetEntry() const {
+ return Path::FromFS(data.cFileName);
+ }
+};
+
+#else
+
#include <dirent.h>
/**
@@ -85,3 +168,5 @@ public:
};
#endif
+
+#endif
diff --git a/src/fs/Domain.cxx b/src/fs/Domain.cxx
index 4f3129219..d278ba1bf 100644
--- a/src/fs/Domain.cxx
+++ b/src/fs/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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 1fd17b37f..77ca64549 100644
--- a/src/fs/Domain.hxx
+++ b/src/fs/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/FileInfo.hxx b/src/fs/FileInfo.hxx
new file mode 100644
index 000000000..7b272568f
--- /dev/null
+++ b/src/fs/FileInfo.hxx
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2003-2015 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_FILE_INFO_HXX
+#define MPD_FS_FILE_INFO_HXX
+
+#include "check.h"
+#include "Path.hxx"
+#include "util/Error.hxx"
+
+#include <stdint.h>
+
+#ifdef WIN32
+#include <fileapi.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#ifdef WIN32
+
+static inline constexpr uint64_t
+ConstructUint64(DWORD lo, DWORD hi)
+{
+ return uint64_t(lo) | (uint64_t(hi) << 32);
+}
+
+static constexpr time_t
+FileTimeToTimeT(FILETIME ft)
+{
+ return (ConstructUint64(ft.dwLowDateTime, ft.dwHighDateTime)
+ - 116444736000000000) / 10000000;
+}
+
+#endif
+
+class FileInfo {
+ friend bool GetFileInfo(Path path, FileInfo &info,
+ bool follow_symlinks);
+ friend bool GetFileInfo(Path path, FileInfo &info,
+ Error &error);
+ friend class FileReader;
+
+#ifdef WIN32
+ WIN32_FILE_ATTRIBUTE_DATA data;
+#else
+ struct stat st;
+#endif
+
+public:
+ bool IsRegular() const {
+#ifdef WIN32
+ return (data.dwFileAttributes &
+ (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)) == 0;
+#else
+ return S_ISREG(st.st_mode);
+#endif
+ }
+
+ bool IsDirectory() const {
+#ifdef WIN32
+ return data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+#else
+ return S_ISDIR(st.st_mode);
+#endif
+ }
+
+ uint64_t GetSize() const {
+#ifdef WIN32
+ return ConstructUint64(data.nFileSizeLow, data.nFileSizeHigh);
+#else
+ return st.st_size;
+#endif
+ }
+
+ time_t GetModificationTime() const {
+#ifdef WIN32
+ return FileTimeToTimeT(data.ftLastWriteTime);
+#else
+ return st.st_mtime;
+#endif
+ }
+
+#ifndef WIN32
+ uid_t GetUid() const {
+ return st.st_uid;
+ }
+
+ mode_t GetMode() const {
+ return st.st_mode;
+ }
+
+ dev_t GetDevice() const {
+ return st.st_dev;
+ }
+
+ ino_t GetInode() const {
+ return st.st_ino;
+ }
+#endif
+};
+
+inline bool
+GetFileInfo(Path path, FileInfo &info, bool follow_symlinks=true)
+{
+#ifdef WIN32
+ (void)follow_symlinks;
+ return GetFileAttributesEx(path.c_str(), GetFileExInfoStandard,
+ &info.data);
+#else
+ int ret = follow_symlinks
+ ? stat(path.c_str(), &info.st)
+ : lstat(path.c_str(), &info.st);
+ return ret == 0;
+#endif
+}
+
+inline bool
+GetFileInfo(Path path, FileInfo &info, bool follow_symlinks, Error &error)
+{
+ bool success = GetFileInfo(path, info, follow_symlinks);
+ if (!success) {
+ const auto path_utf8 = path.ToUTF8();
+#ifdef WIN32
+ error.FormatLastError("Failed to access %s",
+ path_utf8.c_str());
+#else
+ error.FormatErrno("Failed to access %s", path_utf8.c_str());
+#endif
+ }
+
+ return success;
+}
+
+inline bool
+GetFileInfo(Path path, FileInfo &info, Error &error)
+{
+ return GetFileInfo(path, info, true, error);
+}
+
+#endif
diff --git a/src/fs/FileSystem.cxx b/src/fs/FileSystem.cxx
index 4e7c87415..554915b61 100644
--- a/src/fs/FileSystem.cxx
+++ b/src/fs/FileSystem.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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 4dbb064cb..309c0cdf6 100644
--- a/src/fs/FileSystem.hxx
+++ b/src/fs/FileSystem.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,42 +26,27 @@
#include "Path.hxx"
+#ifdef WIN32
+#include <fileapi.h>
+#endif
+
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
+
class AllocatedPath;
namespace FOpenMode {
/**
- * Open mode for reading text files.
- */
- constexpr PathTraitsFS::const_pointer ReadText = "r";
-
- /**
- * Open mode for reading binary files.
- */
- constexpr PathTraitsFS::const_pointer ReadBinary = "rb";
-
- /**
* Open mode for writing text files.
*/
- constexpr PathTraitsFS::const_pointer WriteText = "w";
-
- /**
- * Open mode for writing binary files.
- */
- constexpr PathTraitsFS::const_pointer WriteBinary = "wb";
+ constexpr PathTraitsFS::const_pointer WriteText = PATH_LITERAL("w");
/**
* Open mode for appending text files.
*/
- constexpr PathTraitsFS::const_pointer AppendText = "a";
-
- /**
- * Open mode for appending binary files.
- */
- constexpr PathTraitsFS::const_pointer AppendBinary = "ab";
+ constexpr PathTraitsFS::const_pointer AppendText = PATH_LITERAL("a");
}
/**
@@ -70,7 +55,11 @@ namespace FOpenMode {
static inline FILE *
FOpen(Path file, PathTraitsFS::const_pointer mode)
{
+#ifdef WIN32
+ return _tfopen(file.c_str(), mode);
+#else
return fopen(file.c_str(), mode);
+#endif
}
/**
@@ -79,7 +68,11 @@ FOpen(Path file, PathTraitsFS::const_pointer mode)
static inline int
OpenFile(Path file, int flags, int mode)
{
+#ifdef WIN32
+ return _topen(file.c_str(), flags, mode);
+#else
return open_cloexec(file.c_str(), flags, mode);
+#endif
}
/**
@@ -88,33 +81,40 @@ OpenFile(Path file, int flags, int mode)
static inline bool
RenameFile(Path oldpath, Path newpath)
{
+#ifdef WIN32
+ return _trename(oldpath.c_str(), newpath.c_str()) == 0;
+#else
return rename(oldpath.c_str(), newpath.c_str()) == 0;
+#endif
}
+#ifndef WIN32
+
/**
* Wrapper for stat() that uses #Path names.
*/
static inline bool
StatFile(Path file, struct stat &buf, bool follow_symlinks = true)
{
-#ifdef WIN32
- (void)follow_symlinks;
- return stat(file.c_str(), &buf) == 0;
-#else
int ret = follow_symlinks
? stat(file.c_str(), &buf)
: lstat(file.c_str(), &buf);
return ret == 0;
-#endif
}
+#endif
+
/**
* Wrapper for unlink() that uses #Path names.
*/
static inline bool
RemoveFile(Path file)
{
+#ifdef WIN32
+ return _tunlink(file.c_str()) == 0;
+#else
return unlink(file.c_str()) == 0;
+#endif
}
/**
@@ -143,27 +143,21 @@ CheckAccess(Path path, int mode)
#endif
/**
- * Checks is specified path exists and accessible.
- */
-static inline bool
-CheckAccess(Path path)
-{
-#ifdef WIN32
- struct stat buf;
- return StatFile(path, buf);
-#else
- return CheckAccess(path, F_OK);
-#endif
-}
-
-/**
* Checks if #Path exists and is a regular file.
*/
static inline bool
FileExists(Path path, bool follow_symlinks = true)
{
+#ifdef WIN32
+ (void)follow_symlinks;
+
+ const auto a = GetFileAttributes(path.c_str());
+ return a != INVALID_FILE_ATTRIBUTES &&
+ (a & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)) == 0;
+#else
struct stat buf;
return StatFile(path, buf, follow_symlinks) && S_ISREG(buf.st_mode);
+#endif
}
/**
@@ -172,18 +166,28 @@ FileExists(Path path, bool follow_symlinks = true)
static inline bool
DirectoryExists(Path path, bool follow_symlinks = true)
{
+#ifdef WIN32
+ (void)follow_symlinks;
+
+ const auto a = GetFileAttributes(path.c_str());
+ return a != INVALID_FILE_ATTRIBUTES && (a & FILE_ATTRIBUTE_DIRECTORY);
+#else
struct stat buf;
return StatFile(path, buf, follow_symlinks) && S_ISDIR(buf.st_mode);
+#endif
}
/**
* Checks if #Path exists.
*/
static inline bool
-PathExists(Path path, bool follow_symlinks = true)
+PathExists(Path path)
{
- struct stat buf;
- return StatFile(path, buf, follow_symlinks);
+#ifdef WIN32
+ return GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES;
+#else
+ return CheckAccess(path, F_OK);
+#endif
}
#endif
diff --git a/src/fs/Limits.hxx b/src/fs/Limits.hxx
index 432897a69..b574a9c9a 100644
--- a/src/fs/Limits.hxx
+++ b/src/fs/Limits.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/NarrowPath.hxx b/src/fs/NarrowPath.hxx
new file mode 100644
index 000000000..ad310cd5c
--- /dev/null
+++ b/src/fs/NarrowPath.hxx
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2003-2015 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_NARROW_PATH_HXX
+#define MPD_FS_NARROW_PATH_HXX
+
+#include "check.h"
+#include "Path.hxx"
+#include "util/Macros.hxx"
+
+#ifdef _UNICODE
+#include <windows.h>
+#endif
+
+/**
+ * A path name that uses the regular (narrow) "char". This is used to
+ * pass a #Path (which may be represented by wchar_t) to a library
+ * that accepts only "const char *".
+ */
+class NarrowPath {
+ typedef char value_type;
+ typedef const char *const_pointer;
+
+#ifdef _UNICODE
+ char value[PATH_MAX];
+#else
+ const_pointer value;
+#endif
+
+public:
+#ifdef _UNICODE
+ explicit NarrowPath(Path _path) {
+ auto result = WideCharToMultiByte(CP_ACP, 0,
+ _path.c_str(), -1,
+ value, ARRAY_SIZE(value),
+ nullptr, nullptr);
+ if (result < 0)
+ value[0] = 0;
+ }
+#else
+ explicit NarrowPath(Path _path):value(_path.c_str()) {}
+#endif
+
+ operator const_pointer() const {
+ return value;
+ }
+
+ const_pointer c_str() const {
+ return value;
+ }
+};
+
+#endif
diff --git a/src/fs/Path.cxx b/src/fs/Path.cxx
index 8288a4fec..99a4ffb61 100644
--- a/src/fs/Path.cxx
+++ b/src/fs/Path.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,22 @@
#include "config.h"
#include "Path.hxx"
#include "Charset.hxx"
+#include "util/UriUtil.hxx"
+#include "util/StringUtil.hxx"
std::string
Path::ToUTF8() const
{
return ::PathToUTF8(c_str());
}
+
+Path::const_pointer
+Path::GetSuffix() const
+{
+ const auto base = GetBase().c_str();
+ const auto *dot = StringFindLast(base, '.');
+ if (dot == nullptr || dot == base)
+ return nullptr;
+
+ return dot + 1;
+}
diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx
index 9e0fa5aeb..5e78ea507 100644
--- a/src/fs/Path.hxx
+++ b/src/fs/Path.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,8 @@
#include <assert.h>
#include <string.h>
+class AllocatedPath;
+
/**
* A path name in the native file system character set.
*
@@ -40,7 +42,7 @@ class Path {
typedef PathTraitsFS::pointer pointer;
typedef PathTraitsFS::const_pointer const_pointer;
- const char *value;
+ const_pointer value;
constexpr Path(const_pointer _value):value(_value) {}
@@ -98,7 +100,7 @@ public:
size_t length() const {
assert(value != nullptr);
- return strlen(value);
+ return PathTraitsFS::GetLength(value);
}
/**
@@ -121,6 +123,16 @@ public:
}
/**
+ * Does the path contain a newline character? (Which is
+ * usually rejected by MPD because its protocol cannot
+ * transfer newline characters).
+ */
+ gcc_pure
+ bool HasNewline() const {
+ return PathTraitsFS::Find(value, '\n') != nullptr;
+ }
+
+ /**
* Convert the path to UTF-8.
* Returns empty string on error or if this instance is "nulled"
* (#IsNull returns true).
@@ -129,20 +141,39 @@ public:
std::string ToUTF8() const;
/**
+ * Determine the "base" file name.
+ * The return value points inside this object.
+ */
+ gcc_pure
+ Path GetBase() const {
+ return FromFS(PathTraitsFS::GetBase(value));
+ }
+
+ /**
+ * 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 {
- return PathTraitsFS::Relative(value, other_fs);
+ const_pointer Relative(Path other_fs) const {
+ return PathTraitsFS::Relative(c_str(), other_fs.c_str());
}
gcc_pure
- bool IsAbsolute() {
+ bool IsAbsolute() const {
return PathTraitsFS::IsAbsolute(c_str());
}
+
+ gcc_pure
+ const_pointer GetSuffix() const;
};
#endif
diff --git a/src/fs/Path2.cxx b/src/fs/Path2.cxx
new file mode 100644
index 000000000..b85909f79
--- /dev/null
+++ b/src/fs/Path2.cxx
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2003-2015 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 "Path.hxx"
+#include "AllocatedPath.hxx"
+
+AllocatedPath
+Path::GetDirectoryName() const
+{
+ return AllocatedPath::FromFS(PathTraitsFS::GetParent(c_str()));
+}
diff --git a/src/fs/StandardDirectory.cxx b/src/fs/StandardDirectory.cxx
index 7a836f906..38ea804a0 100644
--- a/src/fs/StandardDirectory.cxx
+++ b/src/fs/StandardDirectory.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -112,7 +112,7 @@ static inline AllocatedPath SafePathFromFS(PathTraitsFS::const_pointer dir)
#ifdef WIN32
static AllocatedPath GetStandardDir(int folder_id)
{
- std::array<char, MAX_PATH> dir;
+ std::array<PathTraitsFS::value_type, MAX_PATH> dir;
auto ret = SHGetFolderPath(nullptr, folder_id | CSIDL_FLAG_DONT_VERIFY,
nullptr, SHGFP_TYPE_CURRENT, dir.data());
if (FAILED(ret))
@@ -287,7 +287,7 @@ AllocatedPath GetSystemConfigDir()
AllocatedPath GetAppBaseDir()
{
- std::array<char, MAX_PATH> app;
+ std::array<PathTraitsFS::value_type, MAX_PATH> app;
auto ret = GetModuleFileName(nullptr, app.data(), app.size());
// Check for error
diff --git a/src/fs/StandardDirectory.hxx b/src/fs/StandardDirectory.hxx
index e3fba375a..d453d109d 100644
--- a/src/fs/StandardDirectory.hxx
+++ b/src/fs/StandardDirectory.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/Traits.cxx b/src/fs/Traits.cxx
index 166b31f4e..e434a779c 100644
--- a/src/fs/Traits.cxx
+++ b/src/fs/Traits.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -74,7 +74,7 @@ GetParentPathImpl(typename Traits::const_pointer p)
typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
if (sep == nullptr)
- return typename Traits::string(".");
+ return typename Traits::string(Traits::CURRENT_DIRECTORY);
if (sep == p)
return typename Traits::string(p, p + 1);
#ifdef WIN32
@@ -98,7 +98,7 @@ RelativePathImpl(typename Traits::const_pointer base,
return nullptr;
other += base_length;
- if (other != 0) {
+ if (*other != 0) {
if (!Traits::IsSeparator(*other))
/* mismatch */
return nullptr;
diff --git a/src/fs/Traits.hxx b/src/fs/Traits.hxx
index 1af8f8672..b92330f60 100644
--- a/src/fs/Traits.hxx
+++ b/src/fs/Traits.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,22 +22,34 @@
#include "check.h"
#include "Compiler.h"
+#include "util/StringAPI.hxx"
#ifdef WIN32
#include "util/CharUtil.hxx"
+#include <tchar.h>
#endif
#include <string>
-#include <string.h>
#include <assert.h>
+#ifdef WIN32
+#define PATH_LITERAL(s) _T(s)
+#else
+#define PATH_LITERAL(s) (s)
+#endif
+
/**
* This class describes the nature of a native filesystem path.
*/
struct PathTraitsFS {
+#ifdef WIN32
+ typedef std::wstring string;
+#else
typedef std::string string;
- typedef char value_type;
+#endif
+ typedef string::traits_type char_traits;
+ typedef char_traits::char_type value_type;
typedef value_type *pointer;
typedef const value_type *const_pointer;
@@ -47,6 +59,8 @@ struct PathTraitsFS {
static constexpr value_type SEPARATOR = '/';
#endif
+ static constexpr const_pointer CURRENT_DIRECTORY = PATH_LITERAL(".");
+
static constexpr bool IsSeparator(value_type ch) {
return
#ifdef WIN32
@@ -68,7 +82,7 @@ struct PathTraitsFS {
--pos;
return IsSeparator(*pos) ? pos : nullptr;
#else
- return strrchr(p, SEPARATOR);
+ return StringFindLast(p, SEPARATOR);
#endif
}
@@ -95,7 +109,12 @@ struct PathTraitsFS {
gcc_pure gcc_nonnull_all
static size_t GetLength(const_pointer p) {
- return strlen(p);
+ return StringLength(p);
+ }
+
+ gcc_pure gcc_nonnull_all
+ static const_pointer Find(const_pointer p, value_type ch) {
+ return StringFind(p, ch);
}
/**
@@ -143,12 +162,15 @@ struct PathTraitsFS {
*/
struct PathTraitsUTF8 {
typedef std::string string;
- typedef char value_type;
+ typedef string::traits_type char_traits;
+ typedef char_traits::char_type value_type;
typedef value_type *pointer;
typedef const value_type *const_pointer;
static constexpr value_type SEPARATOR = '/';
+ static constexpr const_pointer CURRENT_DIRECTORY = ".";
+
static constexpr bool IsSeparator(value_type ch) {
return ch == SEPARATOR;
}
@@ -186,7 +208,12 @@ struct PathTraitsUTF8 {
gcc_pure gcc_nonnull_all
static size_t GetLength(const_pointer p) {
- return strlen(p);
+ return StringLength(p);
+ }
+
+ gcc_pure gcc_nonnull_all
+ static const_pointer Find(const_pointer p, value_type ch) {
+ return StringFind(p, ch);
}
/**
diff --git a/src/fs/io/AutoGunzipReader.cxx b/src/fs/io/AutoGunzipReader.cxx
index 2552f7b99..b6d30dfd7 100644
--- a/src/fs/io/AutoGunzipReader.cxx
+++ b/src/fs/io/AutoGunzipReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/AutoGunzipReader.hxx b/src/fs/io/AutoGunzipReader.hxx
index 9f031e0f5..29a794aed 100644
--- a/src/fs/io/AutoGunzipReader.hxx
+++ b/src/fs/io/AutoGunzipReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/BufferedOutputStream.cxx b/src/fs/io/BufferedOutputStream.cxx
index 088a3e279..2268eb50c 100644
--- a/src/fs/io/BufferedOutputStream.cxx
+++ b/src/fs/io/BufferedOutputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,17 +41,22 @@ bool
BufferedOutputStream::Write(const void *data, size_t size)
{
if (gcc_unlikely(last_error.IsDefined()))
+ /* the stream has already failed */
return false;
+ /* try to append to the current buffer */
if (AppendToBuffer(data, size))
return true;
+ /* not enough room in the buffer - flush it */
if (!Flush())
return false;
+ /* see if there's now enough room */
if (AppendToBuffer(data, size))
return true;
+ /* too large for the buffer: direct write */
return os.Write(data, size, last_error);
}
diff --git a/src/fs/io/BufferedOutputStream.hxx b/src/fs/io/BufferedOutputStream.hxx
index f2de758a2..63a3f4aee 100644
--- a/src/fs/io/BufferedOutputStream.hxx
+++ b/src/fs/io/BufferedOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,6 +30,14 @@
class OutputStream;
class Error;
+/**
+ * An #OutputStream wrapper that buffers its output to reduce the
+ * number of OutputStream::Write() calls.
+ *
+ * It simplifies error handling by managing an #Error attribute.
+ * Invoke any number of writes, and check for errors in the end using
+ * Check().
+ */
class BufferedOutputStream {
OutputStream &os;
@@ -47,11 +55,18 @@ public:
gcc_printf(2,3)
bool Format(const char *fmt, ...);
+ /**
+ * Returns false if an error has occurred.
+ */
gcc_pure
bool Check() const {
return !last_error.IsDefined();
}
+ /**
+ * Returns false if an error has occurred. In that case, a
+ * copy of the #Error is returned.
+ */
bool Check(Error &error) const {
if (last_error.IsDefined()) {
error.Set(last_error);
@@ -60,6 +75,9 @@ public:
return true;
}
+ /**
+ * Write buffer contents to the #OutputStream.
+ */
bool Flush();
bool Flush(Error &error);
diff --git a/src/fs/io/BufferedReader.cxx b/src/fs/io/BufferedReader.cxx
index ba2f17dcf..9a296d815 100644
--- a/src/fs/io/BufferedReader.cxx
+++ b/src/fs/io/BufferedReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -59,8 +59,10 @@ BufferedReader::ReadLine()
{
do {
char *line = ReadBufferedLine(buffer);
- if (line != nullptr)
+ if (line != nullptr) {
+ ++line_number;
return line;
+ }
} while (Fill(true));
if (last_error.IsDefined() || !eof || buffer.IsEmpty())
@@ -78,5 +80,6 @@ BufferedReader::ReadLine()
char *line = buffer.Read().data;
buffer.Clear();
+ ++line_number;
return line;
}
diff --git a/src/fs/io/BufferedReader.hxx b/src/fs/io/BufferedReader.hxx
index 61cc8df83..a0c42d23c 100644
--- a/src/fs/io/BufferedReader.hxx
+++ b/src/fs/io/BufferedReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,9 +41,12 @@ class BufferedReader {
bool eof;
+ unsigned line_number;
+
public:
BufferedReader(Reader &_reader)
- :reader(_reader), buffer(4096), eof(false) {}
+ :reader(_reader), buffer(4096), eof(false),
+ line_number(0) {}
gcc_pure
bool Check() const {
@@ -70,6 +73,10 @@ public:
}
char *ReadLine();
+
+ unsigned GetLineNumber() const {
+ return line_number;
+ }
};
#endif
diff --git a/src/fs/io/FileOutputStream.cxx b/src/fs/io/FileOutputStream.cxx
index 0eff8b5f0..a4ef8f6b4 100644
--- a/src/fs/io/FileOutputStream.cxx
+++ b/src/fs/io/FileOutputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,36 +20,61 @@
#include "config.h"
#include "FileOutputStream.hxx"
#include "fs/FileSystem.hxx"
-#include "system/fd_util.h"
#include "util/Error.hxx"
+FileOutputStream *
+FileOutputStream::Create(Path path, Error &error)
+{
+ FileOutputStream *f = new FileOutputStream(path, error);
+ if (!f->IsDefined()) {
+ delete f;
+ f = nullptr;
+ }
+
+ return f;
+}
+
#ifdef WIN32
FileOutputStream::FileOutputStream(Path _path, Error &error)
- :path(_path),
- handle(CreateFile(path.c_str(), GENERIC_WRITE, 0, nullptr,
- TRUNCATE_EXISTING,
- FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
- nullptr))
+ :BaseFileOutputStream(_path)
{
- if (handle == INVALID_HANDLE_VALUE)
- error.FormatLastError("Failed to create %s", path.c_str());
+ SetHandle(CreateFile(_path.c_str(), GENERIC_WRITE, 0, nullptr,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
+ nullptr));
+ if (!IsDefined())
+ error.FormatLastError("Failed to create %s",
+ GetPath().ToUTF8().c_str());
+}
+
+uint64_t
+BaseFileOutputStream::Tell() const
+{
+ LONG high = 0;
+ DWORD low = SetFilePointer(handle, 0, &high, FILE_CURRENT);
+ if (low == 0xffffffff)
+ return 0;
+
+ return uint64_t(high) << 32 | uint64_t(low);
}
bool
-FileOutputStream::Write(const void *data, size_t size, Error &error)
+BaseFileOutputStream::Write(const void *data, size_t size, Error &error)
{
assert(IsDefined());
DWORD nbytes;
if (!WriteFile(handle, data, size, &nbytes, nullptr)) {
- error.FormatLastError("Failed to write to %s", path.c_str());
+ error.FormatLastError("Failed to write to %s",
+ path.ToUTF8().c_str());
return false;
}
if (size_t(nbytes) != size) {
error.FormatLastError(ERROR_DISK_FULL,
- "Failed to write to %s", path.c_str());
+ "Failed to write to %s",
+ path.ToUTF8().c_str());
return false;
}
@@ -61,8 +86,7 @@ FileOutputStream::Commit(gcc_unused Error &error)
{
assert(IsDefined());
- CloseHandle(handle);
- handle = INVALID_HANDLE_VALUE;
+ Close();
return true;
}
@@ -71,9 +95,8 @@ FileOutputStream::Cancel()
{
assert(IsDefined());
- CloseHandle(handle);
- handle = INVALID_HANDLE_VALUE;
- RemoveFile(path);
+ Close();
+ RemoveFile(GetPath());
}
#else
@@ -82,28 +105,66 @@ FileOutputStream::Cancel()
#include <unistd.h>
#include <errno.h>
+#ifdef HAVE_LINKAT
+#ifndef O_TMPFILE
+/* supported since Linux 3.11 */
+#define __O_TMPFILE 020000000
+#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
+#include <stdio.h>
+#endif
+
+/**
+ * Open a file using Linux's O_TMPFILE for writing the given file.
+ */
+static bool
+OpenTempFile(FileDescriptor &fd, Path path)
+{
+ const auto directory = path.GetDirectoryName();
+ if (directory.IsNull())
+ return false;
+
+ return fd.Open(directory.c_str(), O_TMPFILE|O_WRONLY, 0666);
+}
+
+#endif /* HAVE_LINKAT */
+
FileOutputStream::FileOutputStream(Path _path, Error &error)
- :path(_path),
- fd(open_cloexec(path.c_str(),
- O_WRONLY|O_CREAT|O_TRUNC,
- 0666))
+ :BaseFileOutputStream(_path)
+{
+#ifdef HAVE_LINKAT
+ /* try Linux's O_TMPFILE first */
+ is_tmpfile = OpenTempFile(SetFD(), GetPath());
+ if (!is_tmpfile) {
+#endif
+ /* fall back to plain POSIX */
+ if (!SetFD().Open(GetPath().c_str(),
+ O_WRONLY|O_CREAT|O_TRUNC,
+ 0666))
+ error.FormatErrno("Failed to create %s",
+ GetPath().c_str());
+#ifdef HAVE_LINKAT
+ }
+#endif
+}
+
+uint64_t
+BaseFileOutputStream::Tell() const
{
- if (fd < 0)
- error.FormatErrno("Failed to create %s", path.c_str());
+ return fd.Tell();
}
bool
-FileOutputStream::Write(const void *data, size_t size, Error &error)
+BaseFileOutputStream::Write(const void *data, size_t size, Error &error)
{
assert(IsDefined());
- ssize_t nbytes = write(fd, data, size);
+ ssize_t nbytes = fd.Write(data, size);
if (nbytes < 0) {
- error.FormatErrno("Failed to write to %s", path.c_str());
+ error.FormatErrno("Failed to write to %s", GetPath().c_str());
return false;
} else if ((size_t)nbytes < size) {
error.FormatErrno(ENOSPC,
- "Failed to write to %s", path.c_str());
+ "Failed to write to %s", GetPath().c_str());
return false;
}
@@ -115,10 +176,27 @@ FileOutputStream::Commit(Error &error)
{
assert(IsDefined());
- bool success = close(fd) == 0;
- fd = -1;
+#if HAVE_LINKAT
+ if (is_tmpfile) {
+ RemoveFile(GetPath());
+
+ /* hard-link the temporary file to the final path */
+ char fd_path[64];
+ snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d",
+ GetFD().Get());
+ if (linkat(AT_FDCWD, fd_path, AT_FDCWD, GetPath().c_str(),
+ AT_SYMLINK_FOLLOW) < 0) {
+ error.FormatErrno("Failed to commit %s",
+ GetPath().c_str());
+ Close();
+ return false;
+ }
+ }
+#endif
+
+ bool success = Close();
if (!success)
- error.FormatErrno("Failed to commit %s", path.c_str());
+ error.FormatErrno("Failed to commit %s", GetPath().c_str());
return success;
}
@@ -128,10 +206,53 @@ FileOutputStream::Cancel()
{
assert(IsDefined());
- close(fd);
- fd = -1;
+ Close();
+
+#ifdef HAVE_LINKAT
+ if (!is_tmpfile)
+#endif
+ RemoveFile(GetPath());
+}
+
+#endif
+
+AppendFileOutputStream::AppendFileOutputStream(Path _path, Error &error)
+ :BaseFileOutputStream(_path)
+{
+#ifdef WIN32
+ SetHandle(CreateFile(GetPath().c_str(), GENERIC_WRITE, 0, nullptr,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
+ nullptr));
+ if (!IsDefined())
+ error.FormatLastError("Failed to append to %s",
+ GetPath().ToUTF8().c_str());
- RemoveFile(path);
+ if (!SeekEOF()) {
+ error.FormatLastError("Failed seek end-of-file of %s",
+ GetPath().ToUTF8().c_str());
+ Close();
+ }
+#else
+ if (!SetFD().Open(GetPath().c_str(),
+ O_WRONLY|O_APPEND))
+ error.FormatErrno("Failed to append to %s",
+ GetPath().c_str());
+#endif
}
+bool
+AppendFileOutputStream::Commit(gcc_unused Error &error)
+{
+ assert(IsDefined());
+
+#ifdef WIN32
+ return Close();
+#else
+ bool success = Close();
+ if (!success)
+ error.FormatErrno("Failed to commit %s", GetPath().c_str());
+
+ return success;
#endif
+}
diff --git a/src/fs/io/FileOutputStream.hxx b/src/fs/io/FileOutputStream.hxx
index 5b6309957..b182fd03f 100644
--- a/src/fs/io/FileOutputStream.hxx
+++ b/src/fs/io/FileOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,10 @@
#include "fs/AllocatedPath.hxx"
#include "Compiler.h"
+#ifndef WIN32
+#include "system/FileDescriptor.hxx"
+#endif
+
#include <assert.h>
#ifdef WIN32
@@ -33,37 +37,124 @@
class Path;
-class FileOutputStream final : public OutputStream {
- AllocatedPath path;
+class BaseFileOutputStream : public OutputStream {
+ const AllocatedPath path;
#ifdef WIN32
HANDLE handle;
#else
- int fd;
+ FileDescriptor fd;
#endif
-public:
- FileOutputStream(Path _path, Error &error);
+protected:
+#ifdef WIN32
+ template<typename P>
+ BaseFileOutputStream(P &&_path)
+ :path(std::forward<P>(_path)),
+ handle(INVALID_HANDLE_VALUE) {}
+#else
+ template<typename P>
+ BaseFileOutputStream(P &&_path)
+ :path(std::forward<P>(_path)),
+ fd(FileDescriptor::Undefined()) {}
+#endif
- ~FileOutputStream() {
- if (IsDefined())
- Cancel();
+ ~BaseFileOutputStream() {
+ assert(!IsDefined());
}
+#ifdef WIN32
+ void SetHandle(HANDLE _handle) {
+ assert(!IsDefined());
+
+ handle = _handle;
+
+ assert(IsDefined());
+ }
+#else
+ FileDescriptor &SetFD() {
+ assert(!IsDefined());
+
+ return fd;
+ }
+
+ const FileDescriptor &GetFD() const {
+ return fd;
+ }
+#endif
+
+ bool Close() {
+ assert(IsDefined());
+
+#ifdef WIN32
+ CloseHandle(handle);
+ handle = INVALID_HANDLE_VALUE;
+ return true;
+#else
+ return fd.Close();
+#endif
+ }
+
+#ifdef WIN32
+ bool SeekEOF() {
+ return SetFilePointer(handle, 0, nullptr,
+ FILE_END) != 0xffffffff;
+ }
+#endif
+public:
bool IsDefined() const {
#ifdef WIN32
return handle != INVALID_HANDLE_VALUE;
#else
- return fd >= 0;
+ return fd.IsDefined();
#endif
}
- bool Commit(Error &error);
- void Cancel();
+ Path GetPath() const {
+ return path;
+ }
+
+ gcc_pure
+ uint64_t Tell() const;
/* virtual methods from class OutputStream */
bool Write(const void *data, size_t size, Error &error) override;
};
+class FileOutputStream final : public BaseFileOutputStream {
+#ifdef HAVE_LINKAT
+ /**
+ * Was O_TMPFILE used? If yes, then linkat() must be used to
+ * create a link to this file.
+ */
+ bool is_tmpfile;
+#endif
+
+public:
+ FileOutputStream(Path _path, Error &error);
+
+ ~FileOutputStream() {
+ if (IsDefined())
+ Cancel();
+ }
+
+ static FileOutputStream *Create(Path path, Error &error);
+
+ bool Commit(Error &error);
+ void Cancel();
+};
+
+class AppendFileOutputStream final : public BaseFileOutputStream {
+public:
+ AppendFileOutputStream(Path _path, Error &error);
+
+ ~AppendFileOutputStream() {
+ if (IsDefined())
+ Close();
+ }
+
+ bool Commit(Error &error);
+};
+
#endif
diff --git a/src/fs/io/FileReader.cxx b/src/fs/io/FileReader.cxx
index d63cd8ab0..e54f6f3a8 100644
--- a/src/fs/io/FileReader.cxx
+++ b/src/fs/io/FileReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "FileReader.hxx"
-#include "system/fd_util.h"
+#include "fs/FileInfo.hxx"
#include "util/Error.hxx"
#ifdef WIN32
@@ -30,8 +30,18 @@ FileReader::FileReader(Path _path, Error &error)
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr))
{
- if (handle == INVALID_HANDLE_VALUE)
- error.FormatLastError("Failed to open %s", path.c_str());
+ if (handle == INVALID_HANDLE_VALUE) {
+ const auto path_utf8 = path.ToUTF8();
+ error.FormatLastError("Failed to open %s", path_utf8.c_str());
+ }
+}
+
+bool
+FileReader::GetFileInfo(FileInfo &info, Error &error) const
+{
+ assert(IsDefined());
+
+ return ::GetFileInfo(path, info, error);
}
size_t
@@ -41,13 +51,28 @@ FileReader::Read(void *data, size_t size, Error &error)
DWORD nbytes;
if (!ReadFile(handle, data, size, &nbytes, nullptr)) {
- error.FormatLastError("Failed to read from %s", path.c_str());
+ const auto path_utf8 = path.ToUTF8();
+ error.FormatLastError("Failed to read from %s",
+ path_utf8.c_str());
nbytes = 0;
}
return nbytes;
}
+bool
+FileReader::Seek(off_t offset, Error &error)
+{
+ assert(IsDefined());
+
+ auto result = SetFilePointer(handle, offset, nullptr, FILE_BEGIN);
+ const bool success = result != INVALID_SET_FILE_POINTER;
+ if (!success)
+ error.SetLastError("Failed to seek");
+
+ return success;
+}
+
void
FileReader::Close()
{
@@ -58,26 +83,33 @@ FileReader::Close()
#else
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-
FileReader::FileReader(Path _path, Error &error)
- :path(_path),
- fd(open_cloexec(path.c_str(),
- O_RDONLY,
- 0))
+ :path(_path)
{
- if (fd < 0)
+ fd.OpenReadOnly(path.c_str());
+ if (!fd.IsDefined())
error.FormatErrno("Failed to open %s", path.c_str());
}
+bool
+FileReader::GetFileInfo(FileInfo &info, Error &error) const
+{
+ assert(IsDefined());
+
+ const bool success = fstat(fd.Get(), &info.st) == 0;
+ if (!success)
+ error.FormatErrno("Failed to access %s",
+ path.ToUTF8().c_str());
+
+ return success;
+}
+
size_t
FileReader::Read(void *data, size_t size, Error &error)
{
assert(IsDefined());
- ssize_t nbytes = read(fd, data, size);
+ ssize_t nbytes = fd.Read(data, size);
if (nbytes < 0) {
error.FormatErrno("Failed to read from %s", path.c_str());
nbytes = 0;
@@ -86,13 +118,25 @@ FileReader::Read(void *data, size_t size, Error &error)
return nbytes;
}
+bool
+FileReader::Seek(off_t offset, Error &error)
+{
+ assert(IsDefined());
+
+ auto result = fd.Seek(offset);
+ const bool success = result >= 0;
+ if (!success)
+ error.SetErrno("Failed to seek");
+
+ return success;
+}
+
void
FileReader::Close()
{
assert(IsDefined());
- close(fd);
- fd = -1;
+ fd.Close();
}
#endif
diff --git a/src/fs/io/FileReader.hxx b/src/fs/io/FileReader.hxx
index 9f459aee2..642fc5ed1 100644
--- a/src/fs/io/FileReader.hxx
+++ b/src/fs/io/FileReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,10 @@
#include "fs/AllocatedPath.hxx"
#include "Compiler.h"
+#ifndef WIN32
+#include "system/FileDescriptor.hxx"
+#endif
+
#include <assert.h>
#ifdef WIN32
@@ -32,6 +36,7 @@
#endif
class Path;
+class FileInfo;
class FileReader final : public Reader {
AllocatedPath path;
@@ -39,12 +44,26 @@ class FileReader final : public Reader {
#ifdef WIN32
HANDLE handle;
#else
- int fd;
+ FileDescriptor fd;
#endif
public:
FileReader(Path _path, Error &error);
+#ifdef WIN32
+ FileReader(FileReader &&other)
+ :path(std::move(other.path)),
+ handle(other.handle) {
+ other.handle = INVALID_HANDLE_VALUE;
+ }
+#else
+ FileReader(FileReader &&other)
+ :path(std::move(other.path)),
+ fd(other.fd) {
+ other.fd.SetUndefined();
+ }
+#endif
+
~FileReader() {
if (IsDefined())
Close();
@@ -55,12 +74,22 @@ public:
#ifdef WIN32
return handle != INVALID_HANDLE_VALUE;
#else
- return fd >= 0;
+ return fd.IsDefined();
#endif
}
+#ifndef WIN32
+ FileDescriptor GetFD() const {
+ return fd;
+ }
+#endif
+
void Close();
+ bool GetFileInfo(FileInfo &info, Error &error) const;
+
+ bool Seek(off_t offset, Error &error);
+
/* virtual methods from class Reader */
size_t Read(void *data, size_t size, Error &error) override;
};
diff --git a/src/fs/io/GunzipReader.cxx b/src/fs/io/GunzipReader.cxx
index ad5e41784..78f5b2c69 100644
--- a/src/fs/io/GunzipReader.cxx
+++ b/src/fs/io/GunzipReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/GunzipReader.hxx b/src/fs/io/GunzipReader.hxx
index 06c44bad6..381d1af5e 100644
--- a/src/fs/io/GunzipReader.hxx
+++ b/src/fs/io/GunzipReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/GzipOutputStream.cxx b/src/fs/io/GzipOutputStream.cxx
index 27ae6b2ad..d2a693b87 100644
--- a/src/fs/io/GzipOutputStream.cxx
+++ b/src/fs/io/GzipOutputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/GzipOutputStream.hxx b/src/fs/io/GzipOutputStream.hxx
index 27ee2dd24..fdab7bca4 100644
--- a/src/fs/io/GzipOutputStream.hxx
+++ b/src/fs/io/GzipOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/OutputStream.hxx b/src/fs/io/OutputStream.hxx
index 71311c71f..f7d101180 100644
--- a/src/fs/io/OutputStream.hxx
+++ b/src/fs/io/OutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/PeekReader.cxx b/src/fs/io/PeekReader.cxx
index 2e8042ab6..ec9520a37 100644
--- a/src/fs/io/PeekReader.cxx
+++ b/src/fs/io/PeekReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/PeekReader.hxx b/src/fs/io/PeekReader.hxx
index 32180b0a8..c00ed66be 100644
--- a/src/fs/io/PeekReader.hxx
+++ b/src/fs/io/PeekReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/Reader.hxx b/src/fs/io/Reader.hxx
index d41e92dd0..657f96ac2 100644
--- a/src/fs/io/Reader.hxx
+++ b/src/fs/io/Reader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/StdioOutputStream.hxx b/src/fs/io/StdioOutputStream.hxx
index c1c0a00bd..88dbe6f00 100644
--- a/src/fs/io/StdioOutputStream.hxx
+++ b/src/fs/io/StdioOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 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/io/TextFile.cxx b/src/fs/io/TextFile.cxx
index 28d6dabcb..9866da08a 100644
--- a/src/fs/io/TextFile.cxx
+++ b/src/fs/io/TextFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,14 +28,14 @@
TextFile::TextFile(Path path_fs, Error &error)
:file_reader(new FileReader(path_fs, error)),
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
gunzip_reader(file_reader->IsDefined()
? new AutoGunzipReader(*file_reader)
: nullptr),
#endif
buffered_reader(file_reader->IsDefined()
? new BufferedReader(*
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
gunzip_reader
#else
file_reader
@@ -48,7 +48,7 @@ TextFile::TextFile(Path path_fs, Error &error)
TextFile::~TextFile()
{
delete buffered_reader;
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
delete gunzip_reader;
#endif
delete file_reader;
diff --git a/src/fs/io/TextFile.hxx b/src/fs/io/TextFile.hxx
index 5577363e7..bee9e8c23 100644
--- a/src/fs/io/TextFile.hxx
+++ b/src/fs/io/TextFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@ class BufferedReader;
class TextFile {
FileReader *const file_reader;
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
AutoGunzipReader *const gunzip_reader;
#endif
@@ -59,7 +59,6 @@ public:
* Use Check() after nullptr has been returned to check
* whether an error occurred or end-of-file has been reached.
*
- * @param file the source file, opened in text mode
* @return a pointer to the line, or nullptr on end-of-file or error
*/
char *ReadLine();