diff options
Diffstat (limited to 'src/fs')
42 files changed, 275 insertions, 170 deletions
diff --git a/src/fs/AllocatedPath.cxx b/src/fs/AllocatedPath.cxx index ceaad73ea..45447de69 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); +#ifdef HAVE_FS_CHARSET + return AllocatedPath(::PathFromUTF8(path_utf8)); #else return FromFS(path_utf8); #endif @@ -111,7 +92,7 @@ AllocatedPath::ChopSeparators() 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..7195a3345 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 @@ -44,13 +44,6 @@ class AllocatedPath { string value; - struct Donate {}; - - /** - * Donate the allocated pointer to a new #AllocatedPath object. - */ - AllocatedPath(Donate, pointer _value); - AllocatedPath(const_pointer _value):value(_value) {} AllocatedPath(string &&_value):value(std::move(_value)) {} @@ -169,6 +162,16 @@ 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. diff --git a/src/fs/Charset.cxx b/src/fs/Charset.cxx index c634c9340..cbfe6ea3e 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,66 +21,52 @@ #include "Charset.hxx" #include "Domain.hxx" #include "Limits.hxx" -#include "system/FatalError.hxx" #include "Log.hxx" #include "Traits.hxx" - -#ifdef HAVE_GLIB -#include <glib.h> -#endif +#include "lib/icu/Converter.hxx" +#include "util/Error.hxx" #include <algorithm> #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; - - g_free(test); - return true; -} +static IcuConverter *fs_converter; -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"; @@ -108,43 +94,24 @@ PathToUTF8(const char *path_fs) assert(path_fs != nullptr); #endif -#ifdef HAVE_GLIB - if (fs_charset.empty()) { +#ifdef HAVE_FS_CHARSET + if (fs_converter == nullptr) { #endif auto result = std::string(path_fs); FixSeparators(result); return result; -#ifdef HAVE_GLIB +#ifdef HAVE_FS_CHARSET } - 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(); - - auto result_path = std::string(path_utf8, sizeof(path_utf8) - out_left); + auto result_path = fs_converter->ToUTF8(path_fs); FixSeparators(result_path); return result_path; #endif } -#ifdef HAVE_GLIB +#ifdef HAVE_FS_CHARSET -char * +std::string PathFromUTF8(const char *path_utf8) { #if !CLANG_CHECK_VERSION(3,6) @@ -152,12 +119,10 @@ PathFromUTF8(const char *path_utf8) assert(path_utf8 != nullptr); #endif - if (fs_charset.empty()) - return g_strdup(path_utf8); + 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 diff --git a/src/fs/Charset.hxx b/src/fs/Charset.hxx index 0a71d7c58..dd5ca168a 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 @@ -25,6 +25,12 @@ #include <string> +#if defined(HAVE_ICU) || defined(HAVE_GLIB) +#define HAVE_FS_CHARSET +#endif + +class Error; + /** * Gets file system character set name. */ @@ -32,8 +38,11 @@ gcc_const const char * GetFSCharset(); +bool +SetFSCharset(const char *charset, Error &error); + void -SetFSCharset(const char *charset); +DeinitFSCharset(); /** * Convert the path to UTF-8. @@ -43,8 +52,12 @@ gcc_pure gcc_nonnull_all std::string PathToUTF8(const char *path_fs); -gcc_malloc gcc_nonnull_all -char * +/** + * Convert the path from UTF-8. + * Returns empty string on error. + */ +gcc_pure gcc_nonnull_all +std::string PathFromUTF8(const char *path_utf8); #endif diff --git a/src/fs/CheckFile.cxx b/src/fs/CheckFile.cxx index a35443674..3f44e8397 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 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..cd15952a1 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 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/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..fd88ba572 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 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/Path.cxx b/src/fs/Path.cxx index 8288a4fec..5a21b698f 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 diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx index 9e0fa5aeb..f9cc9839b 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. * @@ -129,6 +131,22 @@ 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 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..1fc76ce9f 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 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..4c8d7012c 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 diff --git a/src/fs/Traits.hxx b/src/fs/Traits.hxx index 1af8f8672..1b5e1e6f8 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 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..7d3cd3815 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 diff --git a/src/fs/io/BufferedOutputStream.hxx b/src/fs/io/BufferedOutputStream.hxx index f2de758a2..9be4c125a 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 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 dc4456d1f..11b5b2351 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,9 +20,20 @@ #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) @@ -80,14 +91,47 @@ 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 int +OpenTempFile(Path path) +{ + const auto directory = path.GetDirectoryName(); + if (directory.IsNull()) + return -1; + + return OpenFile(directory, 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)) + :path(_path) { - if (fd < 0) - error.FormatErrno("Failed to create %s", path.c_str()); +#ifdef HAVE_LINKAT + /* try Linux's O_TMPFILE first */ + fd = OpenTempFile(path); + is_tmpfile = fd >= 0; + if (!is_tmpfile) { +#endif + /* fall back to plain POSIX */ + fd = OpenFile(path, + O_WRONLY|O_CREAT|O_TRUNC, + 0666); + if (fd < 0) + error.FormatErrno("Failed to create %s", path.c_str()); +#ifdef HAVE_LINKAT + } +#endif } bool @@ -113,6 +157,22 @@ FileOutputStream::Commit(Error &error) { assert(IsDefined()); +#if HAVE_LINKAT + if (is_tmpfile) { + RemoveFile(path); + + /* hard-link the temporary file to the final path */ + char fd_path[64]; + snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", fd); + if (linkat(AT_FDCWD, fd_path, AT_FDCWD, path.c_str(), + AT_SYMLINK_FOLLOW) < 0) { + error.FormatErrno("Failed to commit %s", path.c_str()); + close(fd); + return false; + } + } +#endif + bool success = close(fd) == 0; fd = -1; if (!success) @@ -129,7 +189,10 @@ FileOutputStream::Cancel() close(fd); fd = -1; - RemoveFile(path); +#ifdef HAVE_LINKAT + if (!is_tmpfile) +#endif + RemoveFile(path); } #endif diff --git a/src/fs/io/FileOutputStream.hxx b/src/fs/io/FileOutputStream.hxx index 5b6309957..f66554ec9 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 @@ -42,6 +42,14 @@ class FileOutputStream final : public OutputStream { int fd; #endif +#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); @@ -50,6 +58,7 @@ public: Cancel(); } + static FileOutputStream *Create(Path path, Error &error); bool IsDefined() const { #ifdef WIN32 diff --git a/src/fs/io/FileReader.cxx b/src/fs/io/FileReader.cxx index d63cd8ab0..01ffe95f2 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/FileSystem.hxx" #include "util/Error.hxx" #ifdef WIN32 @@ -64,9 +64,9 @@ FileReader::Close() FileReader::FileReader(Path _path, Error &error) :path(_path), - fd(open_cloexec(path.c_str(), - O_RDONLY, - 0)) + fd(OpenFile(path, + O_RDONLY, + 0)) { if (fd < 0) error.FormatErrno("Failed to open %s", path.c_str()); diff --git a/src/fs/io/FileReader.hxx b/src/fs/io/FileReader.hxx index 9f459aee2..96054d936 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 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..b116565d6 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 |