diff options
author | Max Kellermann <max@duempel.org> | 2014-01-29 18:14:57 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-02-05 10:04:03 +0100 |
commit | 9ae7f186bc43749383594807b1d751b5389161e7 (patch) | |
tree | 0cafbfde8316c4b1a9ded19060d3020977a604dd /src/storage | |
parent | f8d114be42663006d162311c1ecaf4306e0b72e4 (diff) | |
download | mpd-9ae7f186bc43749383594807b1d751b5389161e7.tar.gz mpd-9ae7f186bc43749383594807b1d751b5389161e7.tar.xz mpd-9ae7f186bc43749383594807b1d751b5389161e7.zip |
LocalStorage: new API abstracting filesystem walk
Prepare to make this a new plugin API, for example to use a SMB share
for the music_directory.
Diffstat (limited to 'src/storage')
-rw-r--r-- | src/storage/FileInfo.hxx | 62 | ||||
-rw-r--r-- | src/storage/LocalStorage.cxx | 154 | ||||
-rw-r--r-- | src/storage/LocalStorage.hxx | 89 |
3 files changed, 305 insertions, 0 deletions
diff --git a/src/storage/FileInfo.hxx b/src/storage/FileInfo.hxx new file mode 100644 index 000000000..8dd152c0a --- /dev/null +++ b/src/storage/FileInfo.hxx @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_STORAGE_FILE_INFO_HXX +#define MPD_STORAGE_FILE_INFO_HXX + +#include "check.h" + +#include <time.h> +#include <stdint.h> + +struct FileInfo { + enum class Type : uint8_t { + OTHER, + REGULAR, + DIRECTORY, + }; + + Type type; + + /** + * The file size in bytes. Only valid for #Type::REGULAR. + */ + uint64_t size; + + /** + * The modification time. 0 means unknown / not applicable. + */ + time_t mtime; + + /** + * Device id and inode number. 0 means unknown / not + * applicable. + */ + unsigned device, inode; + + bool IsRegular() const { + return type == Type::REGULAR; + } + + bool IsDirectory() const { + return type == Type::DIRECTORY; + } +}; + +#endif diff --git a/src/storage/LocalStorage.cxx b/src/storage/LocalStorage.cxx new file mode 100644 index 000000000..a229b3fe7 --- /dev/null +++ b/src/storage/LocalStorage.cxx @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "LocalStorage.hxx" +#include "FileInfo.hxx" +#include "util/Error.hxx" +#include "fs/FileSystem.hxx" + +static bool +Stat(Path path, bool follow, FileInfo &info, Error &error) +{ + struct stat st; + if (!StatFile(path, st, follow)) { + error.SetErrno(); + + const auto path_utf8 = path.ToUTF8(); + error.FormatPrefix("Failed to stat %s: ", path_utf8.c_str()); + return false; + } + + if (S_ISREG(st.st_mode)) + info.type = FileInfo::Type::REGULAR; + else if (S_ISDIR(st.st_mode)) + info.type = FileInfo::Type::DIRECTORY; + else + info.type = FileInfo::Type::OTHER; + + info.size = st.st_size; + info.mtime = st.st_mtime; + info.device = st.st_dev; + info.inode = st.st_ino; + return true; +} + +std::string +LocalStorage::MapUTF8(const char *uri_utf8) const +{ + assert(uri_utf8 != nullptr); + + if (*uri_utf8 == 0) + return base_utf8; + + return PathTraitsUTF8::Build(base_utf8.c_str(), uri_utf8); +} + +AllocatedPath +LocalStorage::MapFS(const char *uri_utf8, Error &error) const +{ + assert(uri_utf8 != nullptr); + + if (*uri_utf8 == 0) + return base_fs; + + AllocatedPath path_fs = AllocatedPath::FromUTF8(uri_utf8, error); + if (!path_fs.IsNull()) + path_fs = AllocatedPath::Build(base_fs, path_fs); + + return path_fs; +} + +AllocatedPath +LocalStorage::MapFS(const char *uri_utf8) const +{ + return MapFS(uri_utf8, IgnoreError()); +} + +AllocatedPath +LocalStorage::MapChildFS(const char *uri_utf8, + const char *child_utf8) const +{ + const auto uri2 = PathTraitsUTF8::Build(uri_utf8, child_utf8); + return MapFS(uri2.c_str()); +} + +bool +LocalStorage::GetInfo(const char *uri_utf8, bool follow, FileInfo &info, + Error &error) +{ + AllocatedPath path_fs = MapFS(uri_utf8, error); + if (path_fs.IsNull()) + return false; + + return Stat(path_fs, follow, info, error); +} + +LocalDirectoryReader * +LocalStorage::OpenDirectory(const char *uri_utf8, Error &error) +{ + AllocatedPath path_fs = MapFS(uri_utf8, error); + if (path_fs.IsNull()) + return nullptr; + + LocalDirectoryReader *reader = + new LocalDirectoryReader(std::move(path_fs)); + if (reader->HasFailed()) { + error.FormatErrno("Failed to open '%s'", uri_utf8); + delete reader; + return nullptr; + } + + return reader; +} + +gcc_pure +static bool +SkipNameFS(const char *name_fs) +{ + return name_fs[0] == '.' && + (name_fs[1] == 0 || + (name_fs[1] == '.' && name_fs[2] == 0)); +} + +const char * +LocalDirectoryReader::Read() +{ + while (reader.ReadEntry()) { + const Path name_fs = reader.GetEntry(); + if (SkipNameFS(name_fs.c_str())) + continue; + + name_utf8 = name_fs.ToUTF8(); + if (name_utf8.empty()) + continue; + + return name_utf8.c_str(); + } + + return nullptr; +} + +bool +LocalDirectoryReader::GetInfo(bool follow, FileInfo &info, Error &error) +{ + const AllocatedPath path_fs = + AllocatedPath::Build(base_fs, reader.GetEntry()); + return Stat(path_fs, follow, info, error); +} diff --git a/src/storage/LocalStorage.hxx b/src/storage/LocalStorage.hxx new file mode 100644 index 000000000..73c11dd80 --- /dev/null +++ b/src/storage/LocalStorage.hxx @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_STORAGE_LOCAL_HXX +#define MPD_STORAGE_LOCAL_HXX + +#include "check.h" +#include "fs/AllocatedPath.hxx" +#include "fs/DirectoryReader.hxx" + +#include <string> + +struct FileInfo; + +class LocalDirectoryReader { + AllocatedPath base_fs; + + DirectoryReader reader; + + std::string name_utf8; + +public: + LocalDirectoryReader(AllocatedPath &&_base_fs) + :base_fs(std::move(_base_fs)), reader(base_fs) {} + + bool HasFailed() { + return reader.HasFailed(); + } + + const char *Read(); + + bool GetInfo(bool follow, FileInfo &info, Error &error); +}; + +class LocalStorage { + const std::string base_utf8; + const AllocatedPath base_fs; + +public: + LocalStorage(const char *_base_utf8, Path _base_fs) + :base_utf8(_base_utf8), base_fs(_base_fs) {} + + LocalStorage(const LocalStorage &) = delete; + + bool GetInfo(const char *uri_utf8, bool follow, FileInfo &info, + Error &error); + + LocalDirectoryReader *OpenDirectory(const char *uri_utf8, + Error &error); + + /** + * Map the given relative URI to an absolute URI. + */ + gcc_pure + std::string MapUTF8(const char *uri_utf8) const; + + /** + * Map the given relative URI to a local file path. Returns + * AllocatedPath::Null() on error or if this storage does not + * support local files. + */ + gcc_pure + AllocatedPath MapFS(const char *uri_utf8) const; + + gcc_pure + AllocatedPath MapChildFS(const char *uri_utf8, + const char *child_utf8) const; + +private: + AllocatedPath MapFS(const char *uri_utf8, Error &error) const; +}; + +#endif |