From 7d6a7628455ff7a61d139f7643f1d8e4f9938e87 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 22 Jun 2018 22:35:27 +0200 Subject: [PATCH 01/14] python/build/libs.py: upgrade FFmpeg to 4.0.1 --- python/build/libs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/libs.py b/python/build/libs.py index a0818376a..2c47dddb7 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -112,8 +112,8 @@ liblame = AutotoolsProject( ) ffmpeg = FfmpegProject( - 'http://ffmpeg.org/releases/ffmpeg-4.0.tar.xz', - 'ed945daf40b124e77a685893cc025d086f638bc703183460aff49508edb3a43f', + 'http://ffmpeg.org/releases/ffmpeg-4.0.1.tar.xz', + '605f5c01c60db35d3b617a79cabb2c7032412be243554602eeed1b628125c0ee', 'lib/libavcodec.a', [ '--disable-shared', '--enable-static', From 5f082a2739087538d795e12c83f017e5480491b5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 17:28:01 +0200 Subject: [PATCH 02/14] output/httpd: remove broken DLNA support code This code was added in 21851c06733080b4c131d553d5d1f8784c12410f but looks completely broken: - the status code is "206 OK" but "206" would be "Partial Content" - the "Content-Length" header has a bogus value - the "Content-RangeX" parameter has different bogus values (why "Content-RangeX" anyway and not "Content-Range"?) Apart from that, there are strange undocumented non-standard headers which are probably there to work around bugs/expectations in one broken proprietary client product. But these days, MPD doesn't bend over to support broken clients. So let's kill this code. Closes #304 --- NEWS | 2 ++ src/output/plugins/httpd/HttpdClient.cxx | 27 +----------------------- src/output/plugins/httpd/HttpdClient.hxx | 5 ----- 3 files changed, 3 insertions(+), 31 deletions(-) diff --git a/NEWS b/NEWS index 1b0fc1e59..8b8e6591a 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ ver 0.20.21 (not yet released) * database - proxy: add "password" setting - proxy: support tags "ArtistSort", "AlbumArtistSort", "AlbumSort" +* output + - httpd: remove broken DLNA support code ver 0.20.20 (2018/05/22) * protocol diff --git a/src/output/plugins/httpd/HttpdClient.cxx b/src/output/plugins/httpd/HttpdClient.cxx index d5a423d7d..9d3b38c16 100644 --- a/src/output/plugins/httpd/HttpdClient.cxx +++ b/src/output/plugins/httpd/HttpdClient.cxx @@ -122,15 +122,6 @@ HttpdClient::HandleLine(const char *line) return true; } - if (StringEqualsCaseASCII(line, "transferMode.dlna.org: Streaming", 32)) { - /* Send as dlna */ - dlna_streaming_requested = true; - /* metadata is not supported by dlna streaming, so disable it */ - metadata_supported = false; - metadata_requested = false; - return true; - } - /* expect more request headers */ return true; } @@ -148,22 +139,7 @@ HttpdClient::SendResponse() assert(state == RESPONSE); - if (dlna_streaming_requested) { - snprintf(buffer, sizeof(buffer), - "HTTP/1.1 206 OK\r\n" - "Content-Type: %s\r\n" - "Content-Length: 10000\r\n" - "Content-RangeX: 0-1000000/1000000\r\n" - "transferMode.dlna.org: Streaming\r\n" - "Accept-Ranges: bytes\r\n" - "Connection: close\r\n" - "realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n" - "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n" - "\r\n", - httpd.content_type); - response = buffer; - - } else if (metadata_requested) { + if (metadata_requested) { allocated = icy_server_metadata_header(httpd.name, httpd.genre, httpd.website, @@ -202,7 +178,6 @@ HttpdClient::HttpdClient(HttpdOutput &_httpd, int _fd, EventLoop &_loop, state(REQUEST), queue_size(0), head_method(false), - dlna_streaming_requested(false), metadata_supported(_metadata_supported), metadata_requested(false), metadata_sent(true), metaint(8192), /*TODO: just a std value */ diff --git a/src/output/plugins/httpd/HttpdClient.hxx b/src/output/plugins/httpd/HttpdClient.hxx index 3cc337e94..a890833ba 100644 --- a/src/output/plugins/httpd/HttpdClient.hxx +++ b/src/output/plugins/httpd/HttpdClient.hxx @@ -82,11 +82,6 @@ class HttpdClient final */ bool head_method; - /** - * If DLNA streaming was an option. - */ - bool dlna_streaming_requested; - /* ICY */ /** From d5c132fca03ae50eecbeac60524f981eb9d2d81a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 18:25:27 +0200 Subject: [PATCH 03/14] db/update/ExcludeList: move code to ParseLine() --- src/db/update/ExcludeList.cxx | 23 ++++++++++++++--------- src/db/update/ExcludeList.hxx | 3 +++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/db/update/ExcludeList.cxx b/src/db/update/ExcludeList.cxx index e54999f8c..ec44250eb 100644 --- a/src/db/update/ExcludeList.cxx +++ b/src/db/update/ExcludeList.cxx @@ -35,6 +35,18 @@ #include #include +inline void +ExcludeList::ParseLine(char *line) noexcept +{ + char *p = strchr(line, '#'); + if (p != nullptr) + *p = 0; + + p = Strip(line); + if (*p != 0) + patterns.emplace_front(p); +} + bool ExcludeList::LoadFile(Path path_fs) noexcept try { @@ -42,15 +54,8 @@ try { TextFile file(path_fs); char *line; - while ((line = file.ReadLine()) != nullptr) { - char *p = strchr(line, '#'); - if (p != nullptr) - *p = 0; - - p = Strip(line); - if (*p != 0) - patterns.emplace_front(p); - } + while ((line = file.ReadLine()) != nullptr) + ParseLine(line); #else /* not implemented */ (void)path_fs; diff --git a/src/db/update/ExcludeList.hxx b/src/db/update/ExcludeList.hxx index 793a3a162..d27f1c888 100644 --- a/src/db/update/ExcludeList.hxx +++ b/src/db/update/ExcludeList.hxx @@ -69,6 +69,9 @@ public: * the specified file name. */ bool Check(Path name_fs) const noexcept; + +private: + void ParseLine(char *line) noexcept; }; From 63406efcd8f395368b3dc5d1d77e05077d1f5550 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 18:27:17 +0200 Subject: [PATCH 04/14] db/update/ExcludeList: allow comments only at start of line --- NEWS | 1 + src/db/update/ExcludeList.cxx | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 8b8e6591a..2c68bfa10 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ ver 0.20.21 (not yet released) * database - proxy: add "password" setting - proxy: support tags "ArtistSort", "AlbumArtistSort", "AlbumSort" + - simple: allow .mpdignore comments only at start of line * output - httpd: remove broken DLNA support code diff --git a/src/db/update/ExcludeList.cxx b/src/db/update/ExcludeList.cxx index ec44250eb..8f37d09f5 100644 --- a/src/db/update/ExcludeList.cxx +++ b/src/db/update/ExcludeList.cxx @@ -38,12 +38,8 @@ inline void ExcludeList::ParseLine(char *line) noexcept { - char *p = strchr(line, '#'); - if (p != nullptr) - *p = 0; - - p = Strip(line); - if (*p != 0) + char *p = Strip(line); + if (*p != 0 && *p != '#') patterns.emplace_front(p); } From e1ee8e78123a88678b4ebee67e77669257ccb89a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 24 Jan 2018 13:22:43 +0100 Subject: [PATCH 05/14] util/FormatString: remove obsolete Windows fallback Since 7d353bbe2a70cd7894b1f5954a37e4a07890478d, _GNU_SOURCE is always defined, which implies __USE_MINGW_ANSI_STDIO and thus switches to the mingw implementations of the printf() family. That's standards-compliant, unlike Microsoft's CRT implementations. --- src/util/FormatString.cxx | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/util/FormatString.cxx b/src/util/FormatString.cxx index b758997aa..eb216d9b7 100644 --- a/src/util/FormatString.cxx +++ b/src/util/FormatString.cxx @@ -23,14 +23,9 @@ #include #include -#ifdef _WIN32 -#include -#endif - AllocatedString<> FormatStringV(const char *fmt, va_list args) { -#ifndef _WIN32 va_list tmp; va_copy(tmp, args); const int length = vsnprintf(NULL, 0, fmt, tmp); @@ -43,22 +38,6 @@ FormatStringV(const char *fmt, va_list args) char *buffer = new char[length + 1]; vsnprintf(buffer, length + 1, fmt, args); return AllocatedString<>::Donate(buffer); -#else - /* On mingw32, snprintf() expects a 64 bit integer instead of - a "long int" for "%li". This is not consistent with our - expectation, so we're using plain sprintf() here, hoping - the static buffer is large enough. Sorry for this hack, - but WIN32 development is so painful, I'm not in the mood to - do it properly now. */ - - char buffer[16384]; - vsprintf(buffer, fmt, args); - - const size_t length = strlen(buffer); - char *p = new char[length + 1]; - memcpy(p, buffer, length + 1); - return AllocatedString<>::Donate(p); -#endif } AllocatedString<> From 87dfca0477c65945b487d661fa00a93fe15a8eb5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 24 Jan 2018 13:26:18 +0100 Subject: [PATCH 06/14] input/curl: remove obsolete Windows sprintf() fallback See commit be137a191e5bb12f44e5c51205b2e5f86ef7117c --- src/input/plugins/CurlInputPlugin.cxx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 7547b97f4..8def83f46 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -416,12 +416,7 @@ CurlInputStream::SeekInternal(offset_type new_offset) if (offset > 0) { char range[32]; -#ifdef _WIN32 - // TODO: what can we use on Windows to format 64 bit? - sprintf(range, "%lu-", (long)offset); -#else sprintf(range, "%llu-", (unsigned long long)offset); -#endif request->SetOption(CURLOPT_RANGE, range); } From 41cdc4e14b3d36d70039a7ac1578fe7c898a0bac Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 24 Jan 2018 13:25:11 +0100 Subject: [PATCH 07/14] input/Offset: add macro PRIoffset --- src/input/Offset.hxx | 6 ++++++ src/input/plugins/CurlInputPlugin.cxx | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/input/Offset.hxx b/src/input/Offset.hxx index e5d0be21f..725591e6c 100644 --- a/src/input/Offset.hxx +++ b/src/input/Offset.hxx @@ -29,4 +29,10 @@ */ typedef uint64_t offset_type; +/** + * To format an offset_type with printf(). To use this, include + * . + */ +#define PRIoffset PRIu64 + #endif diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 8def83f46..ea48d299b 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -40,6 +40,8 @@ #include "Log.hxx" #include "PluginUnavailable.hxx" +#include + #include #include @@ -416,7 +418,7 @@ CurlInputStream::SeekInternal(offset_type new_offset) if (offset > 0) { char range[32]; - sprintf(range, "%llu-", (unsigned long long)offset); + sprintf(range, "%" PRIoffset "-", offset); request->SetOption(CURLOPT_RANGE, range); } From 60d5bf0240dea58419edb05198906349e81abbe8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 24 Jan 2018 12:52:43 +0100 Subject: [PATCH 08/14] util/StringFormat: new utility library --- Makefile.am | 1 + src/AudioFormat.cxx | 19 ++--- .../plugins/upnp/ContentDirectoryService.cxx | 17 ++--- src/decoder/plugins/GmeDecoderPlugin.cxx | 26 +++---- src/decoder/plugins/SidplayDecoderPlugin.cxx | 14 ++-- src/fs/io/FileOutputStream.cxx | 8 +-- src/input/plugins/CurlInputPlugin.cxx | 21 +++--- src/lib/ffmpeg/LogCallback.cxx | 8 ++- src/output/Init.cxx | 1 + src/protocol/Ack.hxx | 10 +-- src/storage/plugins/CurlStorage.cxx | 5 +- src/tag/TagHandler.cxx | 9 +-- src/thread/Name.hxx | 6 +- src/util/StringFormat.hxx | 69 +++++++++++++++++++ 14 files changed, 132 insertions(+), 82 deletions(-) create mode 100644 src/util/StringFormat.hxx diff --git a/Makefile.am b/Makefile.am index d5416681a..c14823910 100644 --- a/Makefile.am +++ b/Makefile.am @@ -444,6 +444,7 @@ libutil_a_SOURCES = \ src/util/NumberParser.hxx \ src/util/MimeType.cxx src/util/MimeType.hxx \ src/util/StringBuffer.hxx \ + src/util/StringFormat.hxx \ src/util/StringPointer.hxx \ src/util/StringView.cxx src/util/StringView.hxx \ src/util/AllocatedString.cxx src/util/AllocatedString.hxx \ diff --git a/src/AudioFormat.cxx b/src/AudioFormat.cxx index f317d8abe..13d3709f9 100644 --- a/src/AudioFormat.cxx +++ b/src/AudioFormat.cxx @@ -19,9 +19,9 @@ #include "AudioFormat.hxx" #include "util/StringBuffer.hxx" +#include "util/StringFormat.hxx" #include -#include void AudioFormat::ApplyMask(AudioFormat mask) noexcept @@ -44,21 +44,16 @@ AudioFormat::ApplyMask(AudioFormat mask) noexcept StringBuffer<24> ToString(const AudioFormat af) noexcept { - StringBuffer<24> buffer; - if (af.format == SampleFormat::DSD && af.sample_rate > 0 && af.sample_rate % 44100 == 0) { /* use shortcuts such as "dsd64" which implies the sample rate */ - snprintf(buffer.data(), buffer.capacity(), "dsd%u:%u", - af.sample_rate * 8 / 44100, - af.channels); - return buffer; + return StringFormat<24>("dsd%u:%u", + af.sample_rate * 8 / 44100, + af.channels); } - snprintf(buffer.data(), buffer.capacity(), "%u:%s:%u", - af.sample_rate, sample_format_to_string(af.format), - af.channels); - - return buffer; + return StringFormat<24>("%u:%s:%u", + af.sample_rate, sample_format_to_string(af.format), + af.channels); } diff --git a/src/db/plugins/upnp/ContentDirectoryService.cxx b/src/db/plugins/upnp/ContentDirectoryService.cxx index 386a1fcaa..d7aeca82d 100644 --- a/src/db/plugins/upnp/ContentDirectoryService.cxx +++ b/src/db/plugins/upnp/ContentDirectoryService.cxx @@ -27,6 +27,7 @@ #include "util/UriUtil.hxx" #include "util/RuntimeError.hxx" #include "util/ScopeExit.hxx" +#include "util/StringFormat.hxx" #include @@ -47,10 +48,6 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl, unsigned &didreadp, unsigned &totalp) const { - // Create request - char ofbuf[100], cntbuf[100]; - sprintf(ofbuf, "%u", offset); - sprintf(cntbuf, "%u", count); // Some devices require an empty SortCriteria, else bad params IXML_Document *request = MakeActionHelper("Browse", m_serviceType.c_str(), @@ -58,8 +55,10 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl, "BrowseFlag", "BrowseDirectChildren", "Filter", "*", "SortCriteria", "", - "StartingIndex", ofbuf, - "RequestedCount", cntbuf); + "StartingIndex", + StringFormat<32>("%u", offset).c_str(), + "RequestedCount", + StringFormat<32>("%u", count).c_str()); if (request == nullptr) throw std::runtime_error("UpnpMakeAction() failed"); @@ -112,15 +111,13 @@ ContentDirectoryService::search(UpnpClient_Handle hdl, unsigned offset = 0, total = -1, count; do { - char ofbuf[100]; - sprintf(ofbuf, "%d", offset); - UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(), "ContainerID", objectId, "SearchCriteria", ss, "Filter", "*", "SortCriteria", "", - "StartingIndex", ofbuf, + "StartingIndex", + StringFormat<32>("%u", offset).c_str(), "RequestedCount", "0")); // Setting a value here gets twonky into fits if (!request) throw std::runtime_error("UpnpMakeAction() failed"); diff --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx index 1b9d06163..ba0daba63 100644 --- a/src/decoder/plugins/GmeDecoderPlugin.cxx +++ b/src/decoder/plugins/GmeDecoderPlugin.cxx @@ -28,7 +28,7 @@ #include "fs/Path.hxx" #include "fs/AllocatedPath.hxx" #include "util/ScopeExit.hxx" -#include "util/FormatString.hxx" +#include "util/StringFormat.hxx" #include "util/UriUtil.hxx" #include "util/Domain.hxx" #include "Log.hxx" @@ -38,7 +38,6 @@ #include #include #include -#include #define SUBTUNE_PREFIX "tune_" @@ -191,20 +190,17 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count, tag_handler_invoke_duration(handler, handler_ctx, SongTime::FromMS(info.play_length)); - if (track_count > 1) { - char track[16]; - sprintf(track, "%u", song_num + 1); - tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track); - } + if (track_count > 1) + tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, + StringFormat<16>("%u", song_num + 1)); if (info.song != nullptr) { if (track_count > 1) { /* start numbering subtunes from 1 */ - char tag_title[1024]; - snprintf(tag_title, sizeof(tag_title), - "%s (%u/%d)", - info.song, song_num + 1, - track_count); + const auto tag_title = + StringFormat<1024>("%s (%u/%d)", + info.song, song_num + 1, + track_count); tag_handler_invoke_tag(handler, handler_ctx, TAG_TITLE, tag_title); } else @@ -297,9 +293,9 @@ gme_container_scan(Path path_fs) ScanMusicEmu(emu, i, add_tag_handler, &tag_builder); - char track_name[64]; - snprintf(track_name, sizeof(track_name), - SUBTUNE_PREFIX "%03u.%s", i+1, subtune_suffix); + const auto track_name = + StringFormat<64>(SUBTUNE_PREFIX "%03u.%s", i+1, + subtune_suffix); tail = list.emplace_after(tail, track_name, tag_builder.Commit()); } diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx index 3a3c712ef..fc2390ded 100644 --- a/src/decoder/plugins/SidplayDecoderPlugin.cxx +++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx @@ -26,7 +26,7 @@ #include "fs/Path.hxx" #include "fs/AllocatedPath.hxx" #include "util/Macros.hxx" -#include "util/FormatString.hxx" +#include "util/StringFormat.hxx" #include "util/Domain.hxx" #include "system/ByteOrder.hxx" #include "Log.hxx" @@ -413,10 +413,9 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks, title = ""; if (n_tracks > 1) { - char tag_title[1024]; - snprintf(tag_title, sizeof(tag_title), - "%s (%u/%u)", - title, track, n_tracks); + const auto tag_title = + StringFormat<1024>("%s (%u/%u)", + title, track, n_tracks); tag_handler_invoke_tag(handler, handler_ctx, TAG_TITLE, tag_title); } else @@ -435,9 +434,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks, date); /* track */ - char track_buffer[16]; - sprintf(track_buffer, "%d", track); - tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track_buffer); + tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, + StringFormat<16>("%u", track)); } static bool diff --git a/src/fs/io/FileOutputStream.cxx b/src/fs/io/FileOutputStream.cxx index ddf7208a7..e9ce40387 100644 --- a/src/fs/io/FileOutputStream.cxx +++ b/src/fs/io/FileOutputStream.cxx @@ -20,6 +20,7 @@ #include "config.h" #include "FileOutputStream.hxx" #include "system/Error.hxx" +#include "util/StringFormat.hxx" FileOutputStream::FileOutputStream(Path _path, Mode _mode) :path(_path), mode(_mode) @@ -212,10 +213,9 @@ FileOutputStream::Commit() unlink(GetPath().c_str()); /* hard-link the temporary file to the final path */ - char fd_path[64]; - snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", - fd.Get()); - if (linkat(AT_FDCWD, fd_path, AT_FDCWD, path.c_str(), + if (linkat(AT_FDCWD, + StringFormat<64>("/proc/self/fd/%d", fd.Get()), + AT_FDCWD, path.c_str(), AT_SYMLINK_FOLLOW) < 0) throw FormatErrno("Failed to commit %s", path.c_str()); diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index ea48d299b..6e1cf42f2 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -34,6 +34,7 @@ #include "IOThread.hxx" #include "util/ASCII.hxx" #include "util/StringUtil.hxx" +#include "util/StringFormat.hxx" #include "util/NumberParser.hxx" #include "util/RuntimeError.hxx" #include "util/Domain.hxx" @@ -373,13 +374,10 @@ CurlInputStream::InitEasy() if (proxy_port > 0) request->SetOption(CURLOPT_PROXYPORT, (long)proxy_port); - if (proxy_user != nullptr && proxy_password != nullptr) { - char proxy_auth_str[1024]; - snprintf(proxy_auth_str, sizeof(proxy_auth_str), - "%s:%s", - proxy_user, proxy_password); - request->SetOption(CURLOPT_PROXYUSERPWD, proxy_auth_str); - } + if (proxy_user != nullptr && proxy_password != nullptr) + request->SetOption(CURLOPT_PROXYUSERPWD, + StringFormat<1024>("%s:%s", proxy_user, + proxy_password).c_str()); request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1l : 0l); request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l); @@ -416,11 +414,10 @@ CurlInputStream::SeekInternal(offset_type new_offset) /* send the "Range" header */ - if (offset > 0) { - char range[32]; - sprintf(range, "%" PRIoffset "-", offset); - request->SetOption(CURLOPT_RANGE, range); - } + if (offset > 0) + request->SetOption(CURLOPT_RANGE, + StringFormat<40>("%" PRIoffset "-", + offset).c_str()); StartRequest(); } diff --git a/src/lib/ffmpeg/LogCallback.cxx b/src/lib/ffmpeg/LogCallback.cxx index c682da63d..5a0fa4a6f 100644 --- a/src/lib/ffmpeg/LogCallback.cxx +++ b/src/lib/ffmpeg/LogCallback.cxx @@ -25,6 +25,7 @@ #include "Domain.hxx" #include "LogV.hxx" #include "util/Domain.hxx" +#include "util/StringFormat.hxx" extern "C" { #include @@ -57,9 +58,10 @@ FfmpegLogCallback(gcc_unused void *ptr, int level, const char *fmt, va_list vl) cls = *(const AVClass *const*)ptr; if (cls != nullptr) { - char domain[64]; - snprintf(domain, sizeof(domain), "%s/%s", - ffmpeg_domain.GetName(), cls->item_name(ptr)); + const auto domain = + StringFormat<64>("%s/%s", + ffmpeg_domain.GetName(), + cls->item_name(ptr)); const Domain d(domain); LogFormatV(d, FfmpegImportLogLevel(level), fmt, vl); } diff --git a/src/output/Init.cxx b/src/output/Init.cxx index 34b53d916..591219c92 100644 --- a/src/output/Init.cxx +++ b/src/output/Init.cxx @@ -37,6 +37,7 @@ #include "config/ConfigGlobal.hxx" #include "config/Block.hxx" #include "util/RuntimeError.hxx" +#include "util/StringFormat.hxx" #include "Log.hxx" #include diff --git a/src/protocol/Ack.hxx b/src/protocol/Ack.hxx index 195f4bcb0..497f85b18 100644 --- a/src/protocol/Ack.hxx +++ b/src/protocol/Ack.hxx @@ -20,9 +20,9 @@ #ifndef MPD_ACK_H #define MPD_ACK_H -#include +#include "util/StringFormat.hxx" -#include +#include class Domain; @@ -60,9 +60,9 @@ template static inline ProtocolError FormatProtocolError(enum ack code, const char *fmt, Args&&... args) noexcept { - char buffer[256]; - snprintf(buffer, sizeof(buffer), fmt, std::forward(args)...); - return ProtocolError(code, buffer); + return ProtocolError(code, + StringFormat<256>(fmt, + std::forward(args)...)); } #endif diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index 85863cb07..c077b8bb2 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -35,6 +35,7 @@ #include "thread/Cond.hxx" #include "util/RuntimeError.hxx" #include "util/StringCompare.hxx" +#include "util/StringFormat.hxx" #include "util/TimeParser.hxx" #include "util/UriUtil.hxx" @@ -296,9 +297,7 @@ public: { request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND"); - char buffer[40]; - sprintf(buffer, "depth: %u", depth); - request_headers.Append(buffer); + request_headers.Append(StringFormat<40>("depth: %u", depth)); request.SetOption(CURLOPT_HTTPHEADER, request_headers.Get()); diff --git a/src/tag/TagHandler.cxx b/src/tag/TagHandler.cxx index 345c64a21..d59ac9a9c 100644 --- a/src/tag/TagHandler.cxx +++ b/src/tag/TagHandler.cxx @@ -21,8 +21,8 @@ #include "TagHandler.hxx" #include "TagBuilder.hxx" #include "util/ASCII.hxx" +#include "util/StringFormat.hxx" -#include #include static void @@ -42,11 +42,8 @@ add_tag_tag(TagType type, const char *value, void *ctx) /* filter out this extra data and leading zeroes */ char *end; unsigned n = strtoul(value, &end, 10); - if (value != end) { - char s[21]; - if (snprintf(s, 21, "%u", n) > 0) - tag.AddItem(type, s); - } + if (value != end) + tag.AddItem(type, StringFormat<21>("%u", n)); } else tag.AddItem(type, value); } diff --git a/src/thread/Name.hxx b/src/thread/Name.hxx index 20560bfbb..00d5b58da 100644 --- a/src/thread/Name.hxx +++ b/src/thread/Name.hxx @@ -31,7 +31,7 @@ #endif #ifdef HAVE_THREAD_NAME -# include +#include "util/StringFormat.hxx" #endif static inline void @@ -59,9 +59,7 @@ static inline void FormatThreadName(const char *fmt, gcc_unused Args&&... args) { #ifdef HAVE_THREAD_NAME - char buffer[16]; - snprintf(buffer, sizeof(buffer), fmt, args...); - SetThreadName(buffer); + SetThreadName(StringFormat<16>(fmt, args...)); #else (void)fmt; #endif diff --git a/src/util/StringFormat.hxx b/src/util/StringFormat.hxx new file mode 100644 index 000000000..4fee2fc37 --- /dev/null +++ b/src/util/StringFormat.hxx @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010-2015 Max Kellermann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STRING_FORMAT_HXX +#define STRING_FORMAT_HXX + +#include "StringBuffer.hxx" + +#include + +template +static inline void +StringFormat(char *buffer, size_t size, + const char *fmt, Args&&... args) noexcept +{ + snprintf(buffer, size, fmt, args...); +} + +template +static inline void +StringFormat(StringBuffer &buffer, + const char *fmt, Args&&... args) noexcept +{ + StringFormat(buffer.data(), buffer.capacity(), fmt, args...); +} + +template +static inline StringBuffer +StringFormat(const char *fmt, Args&&... args) noexcept +{ + StringBuffer result; + StringFormat(result, fmt, args...); + return result; +} + +template +static inline void +StringFormatUnsafe(char *buffer, const char *fmt, Args&&... args) noexcept +{ + sprintf(buffer, fmt, args...); +} + +#endif From fd7ae7ea4cf09c92c674d317fbd48ba2c6a02ac2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 20 Jan 2018 19:19:07 +0100 Subject: [PATCH 09/14] input/Domain: remove obsolete variable --- Makefile.am | 1 - src/input/AsyncInputStream.cxx | 1 - src/input/Domain.cxx | 24 ------------------------ src/input/Domain.hxx | 27 --------------------------- src/input/Open.cxx | 1 - 5 files changed, 54 deletions(-) delete mode 100644 src/input/Domain.cxx delete mode 100644 src/input/Domain.hxx diff --git a/Makefile.am b/Makefile.am index c14823910..83ff58139 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1293,7 +1293,6 @@ endif # libinput_a_SOURCES = \ - src/input/Domain.cxx src/input/Domain.hxx \ src/input/Init.cxx src/input/Init.hxx \ src/input/Registry.cxx src/input/Registry.hxx \ src/input/Open.cxx \ diff --git a/src/input/AsyncInputStream.cxx b/src/input/AsyncInputStream.cxx index f6e510a1e..1a91d1f58 100644 --- a/src/input/AsyncInputStream.cxx +++ b/src/input/AsyncInputStream.cxx @@ -19,7 +19,6 @@ #include "config.h" #include "AsyncInputStream.hxx" -#include "Domain.hxx" #include "tag/Tag.hxx" #include "thread/Cond.hxx" #include "IOThread.hxx" diff --git a/src/input/Domain.cxx b/src/input/Domain.cxx deleted file mode 100644 index 9d3977fa0..000000000 --- a/src/input/Domain.cxx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2003-2017 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 "Domain.hxx" -#include "util/Domain.hxx" - -const Domain input_domain("input"); diff --git a/src/input/Domain.hxx b/src/input/Domain.hxx deleted file mode 100644 index 1ba83728f..000000000 --- a/src/input/Domain.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2003-2017 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_INPUT_DOMAIN_HXX -#define MPD_INPUT_DOMAIN_HXX - -class Domain; - -extern const Domain input_domain; - -#endif diff --git a/src/input/Open.cxx b/src/input/Open.cxx index a879f24aa..4d2555bdb 100644 --- a/src/input/Open.cxx +++ b/src/input/Open.cxx @@ -22,7 +22,6 @@ #include "Registry.hxx" #include "InputPlugin.hxx" #include "LocalOpen.hxx" -#include "Domain.hxx" #include "plugins/RewindInputPlugin.hxx" #include "fs/Traits.hxx" #include "fs/AllocatedPath.hxx" From 30900b2fe2ac4b365ac5525519a26e61a2b61595 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 19:12:46 +0200 Subject: [PATCH 10/14] input/Error: new library providing IsFileNotFound() --- Makefile.am | 1 + src/input/Error.cxx | 36 ++++++++++++++++++++++++++++++++++++ src/input/Error.hxx | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 src/input/Error.cxx create mode 100644 src/input/Error.hxx diff --git a/Makefile.am b/Makefile.am index 83ff58139..f41f852f6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1293,6 +1293,7 @@ endif # libinput_a_SOURCES = \ + src/input/Error.cxx src/input/Error.hxx \ src/input/Init.cxx src/input/Init.hxx \ src/input/Registry.cxx src/input/Registry.hxx \ src/input/Open.cxx \ diff --git a/src/input/Error.cxx b/src/input/Error.cxx new file mode 100644 index 000000000..04638a16e --- /dev/null +++ b/src/input/Error.cxx @@ -0,0 +1,36 @@ +/* + * Copyright 2003-2018 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 "Error.hxx" +#include "system/Error.hxx" + +bool +IsFileNotFound(std::exception_ptr ep) +{ + try { + std::rethrow_exception(ep); + } catch (const std::system_error &e) { + return IsFileNotFound(e); + } catch (...) { + } + + return false; +} + diff --git a/src/input/Error.hxx b/src/input/Error.hxx new file mode 100644 index 000000000..b52b9d06b --- /dev/null +++ b/src/input/Error.hxx @@ -0,0 +1,37 @@ +/* + * Copyright 2003-2018 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 INPUT_ERROR_HXX +#define INPUT_ERROR_HXX + +#include "check.h" +#include "Compiler.h" + +#include + +/** + * Was this exception thrown because the requested file does not + * exist? This function attempts to recognize exceptions thrown by + * various input plugins. + */ +gcc_pure +bool +IsFileNotFound(std::exception_ptr e); + +#endif From 86e2075c636e2828871e38bf0f2aef4a243c42fd Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 19:01:30 +0200 Subject: [PATCH 11/14] lib/nfs/Connection: use new class NfsClientError Allows callers to extract the NFS error code. --- Makefile.am | 1 + src/input/Error.cxx | 9 +++++ src/lib/nfs/Connection.cxx | 3 +- src/lib/nfs/Error.cxx | 76 ++++++++++++++++++++++++++++++++++++++ src/lib/nfs/Error.hxx | 58 +++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/lib/nfs/Error.cxx create mode 100644 src/lib/nfs/Error.hxx diff --git a/Makefile.am b/Makefile.am index f41f852f6..bbc666ce7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -713,6 +713,7 @@ NFS_SOURCES = \ src/lib/nfs/Cancellable.hxx \ src/lib/nfs/Lease.hxx \ src/lib/nfs/Connection.cxx src/lib/nfs/Connection.hxx \ + src/lib/nfs/Error.cxx src/lib/nfs/Error.hxx \ src/lib/nfs/Manager.cxx src/lib/nfs/Manager.hxx \ src/lib/nfs/Glue.cxx src/lib/nfs/Glue.hxx \ src/lib/nfs/Base.cxx src/lib/nfs/Base.hxx \ diff --git a/src/input/Error.cxx b/src/input/Error.cxx index 04638a16e..ae7b9d7de 100644 --- a/src/input/Error.cxx +++ b/src/input/Error.cxx @@ -21,6 +21,11 @@ #include "Error.hxx" #include "system/Error.hxx" +#ifdef ENABLE_NFS +#include "lib/nfs/Error.hxx" +#include +#endif + bool IsFileNotFound(std::exception_ptr ep) { @@ -28,6 +33,10 @@ IsFileNotFound(std::exception_ptr ep) std::rethrow_exception(ep); } catch (const std::system_error &e) { return IsFileNotFound(e); +#ifdef ENABLE_NFS + } catch (const NfsClientError &e) { + return e.GetCode() == NFS3ERR_NOENT; +#endif } catch (...) { } diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index f9792f41b..cad2da530 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "Connection.hxx" +#include "Error.hxx" #include "Lease.hxx" #include "Callback.hxx" #include "event/Loop.hxx" @@ -139,7 +140,7 @@ NfsConnection::CancellableCallback::Callback(int err, void *data) if (err >= 0) cb.OnNfsCallback((unsigned)err, data); else - cb.OnNfsError(std::make_exception_ptr(std::runtime_error((const char *)data))); + cb.OnNfsError(std::make_exception_ptr(NfsClientError(-err, (const char *)data))); } else { if (open) { /* a nfs_open_async() call was cancelled - to diff --git a/src/lib/nfs/Error.cxx b/src/lib/nfs/Error.cxx new file mode 100644 index 000000000..942e6cabf --- /dev/null +++ b/src/lib/nfs/Error.cxx @@ -0,0 +1,76 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: Max Kellermann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Error.hxx" +#include "util/StringFormat.hxx" + +extern "C" { +#include +} + +#include +#include + +static StringBuffer<256> +FormatNfsClientError(struct nfs_context *nfs, const char *msg) noexcept +{ + assert(msg != nullptr); + + const char *msg2 = nfs_get_error(nfs); + return StringFormat<256>("%s: %s", msg, msg2); +} + +NfsClientError::NfsClientError(struct nfs_context *nfs, const char *msg) noexcept + :std::runtime_error(FormatNfsClientError(nfs, msg).c_str()), + code(0) {} + +static StringBuffer<256> +FormatNfsClientError(int err, struct nfs_context *nfs, void *data, + const char *msg) noexcept +{ + assert(msg != nullptr); + assert(err < 0); + + const char *msg2 = (const char *)data; + if (data == nullptr || *(const char *)data == 0) { + msg2 = nfs_get_error(nfs); + if (msg2 == nullptr) + msg2 = strerror(-err); + } + + return StringFormat<256>("%s: %s", msg, msg2); +} + +NfsClientError::NfsClientError(int err, struct nfs_context *nfs, void *data, + const char *msg) noexcept + :std::runtime_error(FormatNfsClientError(err, nfs, data, msg).c_str()), + code(-err) {} diff --git a/src/lib/nfs/Error.hxx b/src/lib/nfs/Error.hxx new file mode 100644 index 000000000..73ab13e5d --- /dev/null +++ b/src/lib/nfs/Error.hxx @@ -0,0 +1,58 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: Max Kellermann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NFS_ERROR_HXX +#define NFS_ERROR_HXX + +#include + +class NfsClientError : public std::runtime_error { + int code; + +public: + explicit NfsClientError(const char *_msg) noexcept + :std::runtime_error(_msg), code(0) {} + + NfsClientError(int _code, const char *_msg) noexcept + :std::runtime_error(_msg), code(_code) {} + + NfsClientError(struct nfs_context *nfs, const char *msg) noexcept; + + NfsClientError(int err, struct nfs_context *nfs, void *data, + const char *msg) noexcept; + + int GetCode() const noexcept { + return code; + } +}; + +#endif From b8259e604ab6f77f8c0c0d27f0ee095a36d8007b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 17:53:57 +0200 Subject: [PATCH 12/14] db/update/{Walk,ExcludeList}: use InputStream to read .mpdignore Supports .mpdignore on NFS/SMB and others (closes #290). --- src/db/update/ExcludeList.cxx | 19 ++++++------------- src/db/update/ExcludeList.hxx | 3 ++- src/db/update/Walk.cxx | 18 +++++++++++++----- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/db/update/ExcludeList.cxx b/src/db/update/ExcludeList.cxx index 8f37d09f5..332e4bbc7 100644 --- a/src/db/update/ExcludeList.cxx +++ b/src/db/update/ExcludeList.cxx @@ -26,8 +26,8 @@ #include "ExcludeList.hxx" #include "fs/Path.hxx" #include "fs/NarrowPath.hxx" -#include "fs/io/TextFile.hxx" -#include "system/Error.hxx" +#include "input/TextInputStream.hxx" +#include "util/StringUtil.hxx" #include "Log.hxx" #include @@ -44,13 +44,13 @@ ExcludeList::ParseLine(char *line) noexcept } bool -ExcludeList::LoadFile(Path path_fs) noexcept -try { +ExcludeList::Load(InputStreamPtr is) +{ #ifdef HAVE_CLASS_GLOB - TextFile file(path_fs); + TextInputStream tis(std::move(is)); char *line; - while ((line = file.ReadLine()) != nullptr) + while ((line = tis.ReadLine()) != nullptr) ParseLine(line); #else /* not implemented */ @@ -58,13 +58,6 @@ try { #endif return true; -} catch (const std::system_error &e) { - if (!IsFileNotFound(e)) - LogError(e); - return false; -} catch (const std::exception &e) { - LogError(e); - return false; } bool diff --git a/src/db/update/ExcludeList.hxx b/src/db/update/ExcludeList.hxx index d27f1c888..4a851a7dc 100644 --- a/src/db/update/ExcludeList.hxx +++ b/src/db/update/ExcludeList.hxx @@ -28,6 +28,7 @@ #include "check.h" #include "Compiler.h" #include "fs/Glob.hxx" +#include "input/Ptr.hxx" #ifdef HAVE_CLASS_GLOB #include @@ -62,7 +63,7 @@ public: /** * Loads and parses a .mpdignore file. */ - bool LoadFile(Path path_fs) noexcept; + bool Load(InputStreamPtr is); /** * Checks whether one of the patterns in the .mpdignore file matches diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx index 8e58f126d..c71b3d73c 100644 --- a/src/db/update/Walk.cxx +++ b/src/db/update/Walk.cxx @@ -36,6 +36,9 @@ #include "fs/Traits.hxx" #include "fs/FileSystem.hxx" #include "storage/FileInfo.hxx" +#include "input/InputStream.hxx" +#include "input/Error.hxx" +#include "thread/Cond.hxx" #include "util/Alloc.hxx" #include "util/StringCompare.hxx" #include "util/UriUtil.hxx" @@ -345,11 +348,16 @@ UpdateWalk::UpdateDirectory(Directory &directory, ExcludeList child_exclude_list(exclude_list); - { - const auto exclude_path_fs = - storage.MapChildFS(directory.GetPath(), ".mpdignore"); - if (!exclude_path_fs.IsNull()) - child_exclude_list.LoadFile(exclude_path_fs); + try { + Mutex mutex; + Cond cond; + auto is = InputStream::OpenReady(PathTraitsUTF8::Build(storage.MapUTF8(directory.GetPath()).c_str(), + ".mpdignore").c_str(), + mutex, cond); + child_exclude_list.Load(std::move(is)); + } catch (...) { + if (!IsFileNotFound(std::current_exception())) + LogError(std::current_exception()); } if (!child_exclude_list.IsEmpty()) From 466625f7ad9066eeb25383b0ad6f63954b1af9f8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 19:26:11 +0200 Subject: [PATCH 13/14] input/curl: use new class HttpStatusError This way, IsFileNotFound() can detect status 404. --- Makefile.am | 1 + src/input/Error.cxx | 8 +++++ src/input/plugins/CurlInputPlugin.cxx | 5 +++- src/lib/curl/Error.hxx | 42 +++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/lib/curl/Error.hxx diff --git a/Makefile.am b/Makefile.am index bbc666ce7..3ed0c73a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -234,6 +234,7 @@ libmpd_a_SOURCES += \ endif CURL_SOURCES = \ + src/lib/curl/Error.hxx \ src/lib/curl/Version.cxx src/lib/curl/Version.hxx \ src/lib/curl/Global.cxx src/lib/curl/Global.hxx \ src/lib/curl/Request.cxx src/lib/curl/Request.hxx \ diff --git a/src/input/Error.cxx b/src/input/Error.cxx index ae7b9d7de..3db1f26f1 100644 --- a/src/input/Error.cxx +++ b/src/input/Error.cxx @@ -21,6 +21,10 @@ #include "Error.hxx" #include "system/Error.hxx" +#ifdef ENABLE_CURL +#include "lib/curl/Error.hxx" +#endif + #ifdef ENABLE_NFS #include "lib/nfs/Error.hxx" #include @@ -33,6 +37,10 @@ IsFileNotFound(std::exception_ptr ep) std::rethrow_exception(ep); } catch (const std::system_error &e) { return IsFileNotFound(e); +#ifdef ENABLE_CURL + } catch (const HttpStatusError &e) { + return e.GetStatus() == 404; +#endif #ifdef ENABLE_NFS } catch (const NfsClientError &e) { return e.GetCode() == NFS3ERR_NOENT; diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 6e1cf42f2..d9887727f 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "CurlInputPlugin.hxx" +#include "lib/curl/Error.hxx" #include "lib/curl/Easy.hxx" #include "lib/curl/Global.hxx" #include "lib/curl/Request.hxx" @@ -188,7 +189,9 @@ CurlInputStream::OnHeaders(unsigned status, assert(!postponed_exception); if (status < 200 || status >= 300) - throw FormatRuntimeError("got HTTP status %ld", status); + throw HttpStatusError(status, + StringFormat<40>("got HTTP status %u", + status).c_str()); const std::lock_guard protect(mutex); diff --git a/src/lib/curl/Error.hxx b/src/lib/curl/Error.hxx new file mode 100644 index 000000000..4bd68e0c8 --- /dev/null +++ b/src/lib/curl/Error.hxx @@ -0,0 +1,42 @@ +/* + * Copyright 2003-2018 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 CURL_ERROR_HXX +#define CURL_ERROR_HXX + +#include + +/** + * Thrown when an unsuccessful status was received from the HTTP + * server. + */ +class HttpStatusError : public std::runtime_error { + unsigned status; + +public: + template + explicit HttpStatusError(unsigned _status, M &&_msg) noexcept + :std::runtime_error(std::forward(_msg)), status(_status) {} + + unsigned GetStatus() const noexcept { + return status; + } +}; + +#endif From 6f3c0d0a60b0062664320a7beacfd824c0cc6685 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Jul 2018 17:10:11 +0200 Subject: [PATCH 14/14] AudioFormat: include cleanup --- src/AudioFormat.hxx | 1 - src/output/plugins/RoarOutputPlugin.cxx | 2 ++ src/pcm/ConfiguredResampler.cxx | 1 + src/pcm/PcmExport.cxx | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/AudioFormat.hxx b/src/AudioFormat.hxx index 77e710f55..9b01e5256 100644 --- a/src/AudioFormat.hxx +++ b/src/AudioFormat.hxx @@ -23,7 +23,6 @@ #include "pcm/SampleFormat.hxx" #include "Compiler.h" -#include #include #include diff --git a/src/output/plugins/RoarOutputPlugin.cxx b/src/output/plugins/RoarOutputPlugin.cxx index 7a201b2ca..5eb181bc3 100644 --- a/src/output/plugins/RoarOutputPlugin.cxx +++ b/src/output/plugins/RoarOutputPlugin.cxx @@ -36,6 +36,8 @@ #include #undef new +#include + class RoarOutput { friend struct AudioOutputWrapper; diff --git a/src/pcm/ConfiguredResampler.cxx b/src/pcm/ConfiguredResampler.cxx index bd44a95f3..2e68ed89d 100644 --- a/src/pcm/ConfiguredResampler.cxx +++ b/src/pcm/ConfiguredResampler.cxx @@ -35,6 +35,7 @@ #include "SoxrResampler.hxx" #endif +#include #include enum class SelectedResampler { diff --git a/src/pcm/PcmExport.cxx b/src/pcm/PcmExport.cxx index 1054dba4c..b88005cf7 100644 --- a/src/pcm/PcmExport.cxx +++ b/src/pcm/PcmExport.cxx @@ -32,6 +32,8 @@ #include "PcmDop.hxx" #endif +#include + void PcmExport::Open(SampleFormat sample_format, unsigned _channels, Params params)