Merge branch 'v0.21.x' into master

This commit is contained in:
Max Kellermann 2020-09-17 14:43:05 +02:00
commit 0acc398c52
6 changed files with 82 additions and 46 deletions

6
NEWS
View File

@ -40,6 +40,8 @@ ver 0.22 (not yet released)
- GCC 7 or clang 4 (or newer) recommended - GCC 7 or clang 4 (or newer) recommended
ver 0.21.26 (not yet released) ver 0.21.26 (not yet released)
* database
- inotify: obey ".mpdignore" files
* output * output
- osx: fix crash bug - osx: fix crash bug
- sles: support floating point samples - sles: support floating point samples
@ -50,7 +52,11 @@ ver 0.21.26 (not yet released)
- iso9660: support seeking - iso9660: support seeking
- zzip: fix crash on corrupt ZIP file - zzip: fix crash on corrupt ZIP file
* decoder * decoder
- ffmpeg: remove "rtsp://" from the list of supported protocols
- ffmpeg: add "hls+http://" to the list of supported protocols
- sndfile: fix lost samples at end of file - sndfile: fix lost samples at end of file
* fix "single" mode bug after resuming playback
* the default log_level is "default", not "info"
ver 0.21.25 (2020/07/06) ver 0.21.25 (2020/07/06)
* protocol: * protocol:

View File

@ -50,9 +50,7 @@ gcc_pure
static bool static bool
SkipNameFS(PathTraitsFS::const_pointer name_fs) noexcept SkipNameFS(PathTraitsFS::const_pointer name_fs) noexcept
{ {
return name_fs[0] == '.' && return PathTraitsFS::IsSpecialFilename(name_fs);
(name_fs[1] == 0 ||
(name_fs[1] == '.' && name_fs[2] == 0));
} }
gcc_pure gcc_pure

View File

@ -21,19 +21,25 @@
#include "InotifySource.hxx" #include "InotifySource.hxx"
#include "InotifyQueue.hxx" #include "InotifyQueue.hxx"
#include "InotifyDomain.hxx" #include "InotifyDomain.hxx"
#include "ExcludeList.hxx"
#include "storage/StorageInterface.hxx" #include "storage/StorageInterface.hxx"
#include "input/InputStream.hxx"
#include "input/Error.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "fs/DirectoryReader.hxx"
#include "fs/FileInfo.hxx" #include "fs/FileInfo.hxx"
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#include "thread/Mutex.hxx"
#include "util/Compiler.h"
#include "Log.hxx" #include "Log.hxx"
#include <cassert> #include <cassert>
#include <cstring>
#include <forward_list> #include <forward_list>
#include <map> #include <map>
#include <string> #include <string>
#include <sys/inotify.h> #include <sys/inotify.h>
#include <string.h>
#include <dirent.h> #include <dirent.h>
static constexpr unsigned IN_MASK = static constexpr unsigned IN_MASK =
@ -50,17 +56,28 @@ struct WatchDirectory {
int descriptor; int descriptor;
ExcludeList exclude_list;
std::forward_list<WatchDirectory> children; std::forward_list<WatchDirectory> children;
template<typename N> template<typename N>
WatchDirectory(WatchDirectory *_parent, N &&_name, WatchDirectory(N &&_name,
int _descriptor) int _descriptor)
:parent(_parent), name(std::forward<N>(_name)), :parent(nullptr), name(std::forward<N>(_name)),
descriptor(_descriptor) {} descriptor(_descriptor) {}
template<typename N>
WatchDirectory(WatchDirectory &_parent, N &&_name,
int _descriptor)
:parent(&_parent), name(std::forward<N>(_name)),
descriptor(_descriptor),
exclude_list(_parent.exclude_list) {}
WatchDirectory(const WatchDirectory &) = delete; WatchDirectory(const WatchDirectory &) = delete;
WatchDirectory &operator=(const WatchDirectory &) = delete; WatchDirectory &operator=(const WatchDirectory &) = delete;
void LoadExcludeList(Path directory_path) noexcept;
[[nodiscard]] gcc_pure [[nodiscard]] gcc_pure
unsigned GetDepth() const noexcept; unsigned GetDepth() const noexcept;
@ -68,6 +85,18 @@ struct WatchDirectory {
AllocatedPath GetUriFS() const noexcept; AllocatedPath GetUriFS() const noexcept;
}; };
void
WatchDirectory::LoadExcludeList(Path directory_path) noexcept
try {
Mutex mutex;
auto is = InputStream::OpenReady((directory_path / Path::FromFS(".mpdignore")).c_str(),
mutex);
exclude_list.Load(std::move(is));
} catch (...) {
if (!IsFileNotFound(std::current_exception()))
LogError(std::current_exception());
}
static InotifySource *inotify_source; static InotifySource *inotify_source;
static InotifyQueue *inotify_queue; static InotifyQueue *inotify_queue;
@ -145,20 +174,19 @@ WatchDirectory::GetUriFS() const noexcept
} }
/* we don't look at "." / ".." nor files with newlines in their name */ /* we don't look at "." / ".." nor files with newlines in their name */
static bool skip_path(const char *path) gcc_pure
static bool
SkipFilename(Path name) noexcept
{ {
return PathTraitsFS::IsSpecialFilename(path) || return PathTraitsFS::IsSpecialFilename(name.c_str()) ||
std::strchr(path, '\n') != nullptr; name.HasNewline();
} }
static void static void
recursive_watch_subdirectories(WatchDirectory *directory, recursive_watch_subdirectories(WatchDirectory &parent,
const AllocatedPath &path_fs, unsigned depth) const Path path_fs,
{ unsigned depth)
DIR *dir; try {
struct dirent *ent;
assert(directory != nullptr);
assert(depth <= inotify_max_depth); assert(depth <= inotify_max_depth);
assert(!path_fs.IsNull()); assert(!path_fs.IsNull());
@ -167,20 +195,17 @@ recursive_watch_subdirectories(WatchDirectory *directory,
if (depth > inotify_max_depth) if (depth > inotify_max_depth)
return; return;
dir = opendir(path_fs.c_str()); DirectoryReader dir(path_fs);
if (dir == nullptr) { while (dir.ReadEntry()) {
FormatErrno(inotify_domain,
"Failed to open directory %s", path_fs.c_str());
return;
}
while ((ent = readdir(dir))) {
int ret; int ret;
if (skip_path(ent->d_name)) const Path name_fs = dir.GetEntry();
if (SkipFilename(name_fs))
continue;
if (parent.exclude_list.Check(name_fs))
continue; continue;
const auto name_fs = Path::FromFS(ent->d_name);
const auto child_path_fs = path_fs / name_fs; const auto child_path_fs = path_fs / name_fs;
FileInfo fi; FileInfo fi;
@ -209,17 +234,18 @@ recursive_watch_subdirectories(WatchDirectory *directory,
/* already being watched */ /* already being watched */
continue; continue;
directory->children.emplace_front(directory, parent.children.emplace_front(parent,
name_fs, name_fs,
ret); ret);
child = &directory->children.front(); child = &parent.children.front();
child->LoadExcludeList(child_path_fs);
tree_add_watch_directory(child); tree_add_watch_directory(child);
recursive_watch_subdirectories(child, child_path_fs, depth); recursive_watch_subdirectories(*child, child_path_fs, depth);
} }
} catch (...) {
closedir(dir); LogError(std::current_exception());
} }
gcc_pure gcc_pure
@ -240,8 +266,6 @@ mpd_inotify_callback(int wd, unsigned mask,
{ {
WatchDirectory *directory; WatchDirectory *directory;
/*FormatDebug(inotify_domain, "wd=%d mask=0x%x name='%s'", wd, mask, name);*/
directory = tree_find_watch_directory(wd); directory = tree_find_watch_directory(wd);
if (directory == nullptr) if (directory == nullptr)
return; return;
@ -263,7 +287,7 @@ mpd_inotify_callback(int wd, unsigned mask,
? root ? root
: (root / uri_fs); : (root / uri_fs);
recursive_watch_subdirectories(directory, path_fs, recursive_watch_subdirectories(*directory, path_fs,
directory->GetDepth()); directory->GetDepth());
} }
@ -318,11 +342,12 @@ mpd_inotify_init(EventLoop &loop, Storage &storage, UpdateService &update,
return; return;
} }
inotify_root = new WatchDirectory(nullptr, path, descriptor); inotify_root = new WatchDirectory(path, descriptor);
inotify_root->LoadExcludeList(path);
tree_add_watch_directory(inotify_root); tree_add_watch_directory(inotify_root);
recursive_watch_subdirectories(inotify_root, path, 0); recursive_watch_subdirectories(*inotify_root, path, 0);
inotify_queue = new InotifyQueue(loop, update); inotify_queue = new InotifyQueue(loop, update);

View File

@ -443,7 +443,7 @@ Player::ActivateDecoder() noexcept
pc.audio_format.Clear(); pc.audio_format.Clear();
{ {
/* call syncPlaylistWithQueue() in the main thread */ /* call playlist::SyncWithPlayer() in the main thread */
const ScopeUnlock unlock(pc.mutex); const ScopeUnlock unlock(pc.mutex);
pc.listener.OnPlayerSync(); pc.listener.OnPlayerSync();
} }
@ -684,6 +684,12 @@ Player::SeekDecoder(std::unique_lock<Mutex> &lock) noexcept
/* re-fill the buffer after seeking */ /* re-fill the buffer after seeking */
buffering = true; buffering = true;
{
/* call syncPlaylistWithQueue() in the main thread */
const ScopeUnlock unlock(pc.mutex);
pc.listener.OnPlayerSync();
}
return true; return true;
} }
@ -1175,6 +1181,11 @@ try {
{ {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
do_play(*this, dc, buffer); do_play(*this, dc, buffer);
/* give the main thread a chance to
queue another song, just in case
we've stopped playback
spuriously */
listener.OnPlayerSync(); listener.OnPlayerSync();
} }

View File

@ -305,9 +305,7 @@ gcc_pure
static bool static bool
SkipNameFS(PathTraitsFS::const_pointer name) noexcept SkipNameFS(PathTraitsFS::const_pointer name) noexcept
{ {
return name[0] == '.' && return PathTraitsFS::IsSpecialFilename(name);
(name[1] == 0 ||
(name[1] == '.' && name[2] == 0));
} }
static void static void

View File

@ -151,11 +151,9 @@ SmbclientStorage::OpenDirectory(std::string_view uri_utf8)
gcc_pure gcc_pure
static bool static bool
SkipNameFS(const char *name) noexcept SkipNameFS(PathTraitsFS::const_pointer name) noexcept
{ {
return name[0] == '.' && return PathTraitsFS::IsSpecialFilename(name);
(name[1] == 0 ||
(name[1] == '.' && name[2] == 0));
} }
SmbclientDirectoryReader::~SmbclientDirectoryReader() SmbclientDirectoryReader::~SmbclientDirectoryReader()