diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/PlaylistFile.cxx | 7 | ||||
-rw-r--r-- | src/SongUpdate.cxx | 8 | ||||
-rw-r--r-- | src/client/ClientFile.cxx | 10 | ||||
-rw-r--r-- | src/command/FileCommands.cxx | 14 | ||||
-rw-r--r-- | src/db/plugins/simple/SimpleDatabasePlugin.cxx | 32 | ||||
-rw-r--r-- | src/db/update/InotifyUpdate.cxx | 15 | ||||
-rw-r--r-- | src/fs/CheckFile.cxx | 16 | ||||
-rw-r--r-- | src/fs/FileInfo.hxx | 106 | ||||
-rw-r--r-- | src/output/plugins/FifoOutputPlugin.cxx | 5 | ||||
-rw-r--r-- | src/storage/plugins/LocalStorage.cxx | 27 |
11 files changed, 171 insertions, 70 deletions
diff --git a/Makefile.am b/Makefile.am index d61ef66a0..bb87c74b9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -556,6 +556,7 @@ libfs_a_SOURCES = \ src/fs/Path.cxx src/fs/Path2.cxx src/fs/Path.hxx \ src/fs/AllocatedPath.cxx src/fs/AllocatedPath.hxx \ src/fs/FileSystem.cxx src/fs/FileSystem.hxx \ + src/fs/FileInfo.hxx \ src/fs/StandardDirectory.cxx src/fs/StandardDirectory.hxx \ src/fs/CheckFile.cxx src/fs/CheckFile.hxx \ src/fs/DirectoryReader.hxx diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx index f77d1930f..4c2f8d22e 100644 --- a/src/PlaylistFile.cxx +++ b/src/PlaylistFile.cxx @@ -35,6 +35,7 @@ #include "fs/Traits.hxx" #include "fs/Charset.hxx" #include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "fs/DirectoryReader.hxx" #include "util/StringUtil.hxx" #include "util/UriUtil.hxx" @@ -178,8 +179,8 @@ LoadPlaylistFileInfo(PlaylistInfo &info, return false; const auto path_fs = AllocatedPath::Build(parent_path_fs, name_fs); - struct stat st; - if (!StatFile(path_fs, st) || !S_ISREG(st.st_mode)) + FileInfo fi; + if (!GetFileInfo(path_fs, fi) || !fi.IsRegular()) return false; std::string name(name_fs_str, @@ -189,7 +190,7 @@ LoadPlaylistFileInfo(PlaylistInfo &info, return false; info.name = std::move(name_utf8); - info.mtime = st.st_mtime; + info.mtime = fi.GetModificationTime(); return true; } diff --git a/src/SongUpdate.cxx b/src/SongUpdate.cxx index 931f43e1f..6d51055c2 100644 --- a/src/SongUpdate.cxx +++ b/src/SongUpdate.cxx @@ -27,7 +27,7 @@ #include "util/Error.hxx" #include "fs/AllocatedPath.hxx" #include "fs/Traits.hxx" -#include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "decoder/DecoderList.hxx" #include "tag/Tag.hxx" #include "tag/TagBuilder.hxx" @@ -148,8 +148,8 @@ DetachedSong::Update() const AllocatedPath path_fs = AllocatedPath::FromUTF8(GetRealURI()); - struct stat st; - if (!StatFile(path_fs, st) || !S_ISREG(st.st_mode)) + FileInfo fi; + if (!GetFileInfo(path_fs, fi) || !fi.IsRegular()) return false; TagBuilder tag_builder; @@ -160,7 +160,7 @@ DetachedSong::Update() tag_scan_fallback(path_fs, &full_tag_handler, &tag_builder); - mtime = st.st_mtime; + mtime = fi.GetModificationTime(); tag_builder.Commit(tag); return true; } else if (IsRemote()) { diff --git a/src/client/ClientFile.cxx b/src/client/ClientFile.cxx index 9bf977704..72e9d9931 100644 --- a/src/client/ClientFile.cxx +++ b/src/client/ClientFile.cxx @@ -21,7 +21,7 @@ #include "Client.hxx" #include "protocol/Ack.hxx" #include "fs/Path.hxx" -#include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "util/Error.hxx" #include <sys/stat.h> @@ -47,13 +47,11 @@ Client::AllowFile(Path path_fs, Error &error) const return false; } - struct stat st; - if (!StatFile(path_fs, st)) { - error.SetErrno(); + FileInfo fi; + if (!GetFileInfo(path_fs, fi, error)) return false; - } - if (st.st_uid != (uid_t)uid && (st.st_mode & 0444) != 0444) { + if (fi.GetUid() != (uid_t)uid && (fi.GetMode() & 0444) != 0444) { /* client is not owner */ error.Set(ack_domain, ACK_ERROR_PERMISSION, "Access denied"); return false; diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx index f1cb72c99..9f1c3a8e3 100644 --- a/src/command/FileCommands.cxx +++ b/src/command/FileCommands.cxx @@ -36,7 +36,7 @@ #include "TagFile.hxx" #include "storage/StorageInterface.hxx" #include "fs/AllocatedPath.hxx" -#include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "fs/DirectoryReader.hxx" #include "TimePrint.hxx" #include "ls.hxx" @@ -99,22 +99,22 @@ handle_listfiles_local(Client &client, const char *path_utf8) const AllocatedPath full_fs = AllocatedPath::Build(path_fs, name_fs); - struct stat st; - if (!StatFile(full_fs, st, false)) + FileInfo fi; + if (!GetFileInfo(full_fs, fi, false)) continue; - if (S_ISREG(st.st_mode)) { + if (fi.IsRegular()) client_printf(client, "file: %s\n" "size: %" PRIu64 "\n", name_utf8.c_str(), - uint64_t(st.st_size)); - } else if (S_ISDIR(st.st_mode)) + fi.GetSize()); + else if (fi.IsDirectory()) client_printf(client, "directory: %s\n", name_utf8.c_str()); else continue; - time_print(client, "Last-Modified", st.st_mtime); + time_print(client, "Last-Modified", fi.GetModificationTime()); } return CommandResult::OK; diff --git a/src/db/plugins/simple/SimpleDatabasePlugin.cxx b/src/db/plugins/simple/SimpleDatabasePlugin.cxx index 913141d22..39dbcf8b7 100644 --- a/src/db/plugins/simple/SimpleDatabasePlugin.cxx +++ b/src/db/plugins/simple/SimpleDatabasePlugin.cxx @@ -34,6 +34,7 @@ #include "fs/io/TextFile.hxx" #include "fs/io/BufferedOutputStream.hxx" #include "fs/io/FileOutputStream.hxx" +#include "fs/FileInfo.hxx" #include "config/Block.hxx" #include "fs/FileSystem.hxx" #include "util/CharUtil.hxx" @@ -124,15 +125,13 @@ SimpleDatabase::Check(Error &error) const const auto dirPath = path.GetDirectoryName(); /* Check that the parent part of the path is a directory */ - struct stat st; - if (!StatFile(dirPath, st)) { - error.FormatErrno("Couldn't stat parent directory of db file " - "\"%s\"", - path_utf8.c_str()); + FileInfo fi; + if (!GetFileInfo(dirPath, fi, error)) { + error.AddPrefix("On parent directory of db file: "); return false; } - if (!S_ISDIR(st.st_mode)) { + if (!fi.IsDirectory()) { error.Format(simple_db_domain, "Couldn't create db file \"%s\" because the " "parent path is not a directory", @@ -154,14 +153,11 @@ SimpleDatabase::Check(Error &error) const } /* Path exists, now check if it's a regular file */ - struct stat st; - if (!StatFile(path, st)) { - error.FormatErrno("Couldn't stat db file \"%s\"", - path_utf8.c_str()); + FileInfo fi; + if (!GetFileInfo(path, fi, error)) return false; - } - if (!S_ISREG(st.st_mode)) { + if (!fi.IsRegular()) { error.Format(simple_db_domain, "db file \"%s\" is not a regular file", path_utf8.c_str()); @@ -193,9 +189,9 @@ SimpleDatabase::Load(Error &error) if (!db_load_internal(file, *root, error) || !file.Check(error)) return false; - struct stat st; - if (StatFile(path, st)) - mtime = st.st_mtime; + FileInfo fi; + if (GetFileInfo(path, fi)) + mtime = fi.GetModificationTime(); return true; } @@ -425,9 +421,9 @@ SimpleDatabase::Save(Error &error) if (!fos.Commit(error)) return false; - struct stat st; - if (StatFile(path, st)) - mtime = st.st_mtime; + FileInfo fi; + if (GetFileInfo(path, fi)) + mtime = fi.GetModificationTime(); return true; } diff --git a/src/db/update/InotifyUpdate.cxx b/src/db/update/InotifyUpdate.cxx index 42423e07e..f699b7f78 100644 --- a/src/db/update/InotifyUpdate.cxx +++ b/src/db/update/InotifyUpdate.cxx @@ -24,7 +24,7 @@ #include "InotifyDomain.hxx" #include "storage/StorageInterface.hxx" #include "fs/AllocatedPath.hxx" -#include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "util/Error.hxx" #include "Log.hxx" @@ -179,7 +179,6 @@ recursive_watch_subdirectories(WatchDirectory *directory, } while ((ent = readdir(dir))) { - struct stat st; int ret; if (skip_path(ent->d_name)) @@ -187,15 +186,15 @@ recursive_watch_subdirectories(WatchDirectory *directory, const auto child_path_fs = AllocatedPath::Build(path_fs, ent->d_name); - ret = StatFile(child_path_fs, st); - if (ret < 0) { - FormatErrno(inotify_domain, - "Failed to stat %s", - child_path_fs.c_str()); + + FileInfo fi; + if (!GetFileInfo(child_path_fs, fi, error)) { + LogError(error); + error.Clear(); continue; } - if (!S_ISDIR(st.st_mode)) + if (!fi.IsDirectory()) continue; ret = inotify_source->Add(child_path_fs.c_str(), IN_MASK, diff --git a/src/fs/CheckFile.cxx b/src/fs/CheckFile.cxx index bd1798094..0068db639 100644 --- a/src/fs/CheckFile.cxx +++ b/src/fs/CheckFile.cxx @@ -21,7 +21,7 @@ #include "CheckFile.hxx" #include "Log.hxx" #include "config/ConfigError.hxx" -#include "FileSystem.hxx" +#include "FileInfo.hxx" #include "Path.hxx" #include "AllocatedPath.hxx" #include "DirectoryReader.hxx" @@ -32,15 +32,15 @@ void CheckDirectoryReadable(Path path_fs) { - struct stat st; - if (!StatFile(path_fs, st)) { - FormatErrno(config_domain, - "Failed to stat directory \"%s\"", - path_fs.c_str()); + Error error; + + FileInfo fi; + if (!GetFileInfo(path_fs, fi, error)) { + LogError(error); return; } - if (!S_ISDIR(st.st_mode)) { + if (!fi.IsDirectory()) { FormatError(config_domain, "Not a directory: %s", path_fs.c_str()); return; @@ -49,7 +49,7 @@ CheckDirectoryReadable(Path path_fs) #ifndef WIN32 const auto x = AllocatedPath::Build(path_fs, PathTraitsFS::CURRENT_DIRECTORY); - if (!StatFile(x, st) && errno == EACCES) + if (!GetFileInfo(x, fi) && errno == EACCES) FormatError(config_domain, "No permission to traverse (\"execute\") directory: %s", path_fs.c_str()); diff --git a/src/fs/FileInfo.hxx b/src/fs/FileInfo.hxx new file mode 100644 index 000000000..6fe24cb90 --- /dev/null +++ b/src/fs/FileInfo.hxx @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2003-2015 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_FS_FILE_INFO_HXX +#define MPD_FS_FILE_INFO_HXX + +#include "check.h" +#include "Path.hxx" +#include "util/Error.hxx" + +#include <stdint.h> +#include <sys/stat.h> + +class FileInfo { + friend bool GetFileInfo(Path path, FileInfo &info, + bool follow_symlinks); + friend bool GetFileInfo(Path path, FileInfo &info, + Error &error); + + struct stat st; + +public: + bool IsRegular() const { + return S_ISREG(st.st_mode); + } + + bool IsDirectory() const { + return S_ISDIR(st.st_mode); + } + + uint64_t GetSize() const { + return st.st_size; + } + + time_t GetModificationTime() const { + return st.st_mtime; + } + +#ifndef WIN32 + uid_t GetUid() const { + return st.st_uid; + } + + mode_t GetMode() const { + return st.st_mode; + } + + dev_t GetDevice() const { + return st.st_dev; + } + + ino_t GetInode() const { + return st.st_ino; + } +#endif +}; + +inline bool +GetFileInfo(Path path, FileInfo &info, bool follow_symlinks=true) +{ +#ifdef WIN32 + (void)follow_symlinks; + return stat(path.c_str(), &info.st) == 0; +#else + int ret = follow_symlinks + ? stat(path.c_str(), &info.st) + : lstat(path.c_str(), &info.st); + return ret == 0; +#endif +} + +inline bool +GetFileInfo(Path path, FileInfo &info, bool follow_symlinks, Error &error) +{ + bool success = GetFileInfo(path, info, follow_symlinks); + if (!success) { + const auto path_utf8 = path.ToUTF8(); + error.FormatErrno("Failed to access %s", path_utf8.c_str()); + } + + return success; +} + +inline bool +GetFileInfo(Path path, FileInfo &info, Error &error) +{ + return GetFileInfo(path, info, true, error); +} + +#endif diff --git a/src/output/plugins/FifoOutputPlugin.cxx b/src/output/plugins/FifoOutputPlugin.cxx index 05400fe83..6611a83c4 100644 --- a/src/output/plugins/FifoOutputPlugin.cxx +++ b/src/output/plugins/FifoOutputPlugin.cxx @@ -25,6 +25,7 @@ #include "../Timer.hxx" #include "fs/AllocatedPath.hxx" #include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "Log.hxx" @@ -105,8 +106,8 @@ FifoOutput::Close() output = -1; } - struct stat st; - if (created && StatFile(path, st)) + FileInfo fi; + if (created && GetFileInfo(path, fi)) Delete(); } diff --git a/src/storage/plugins/LocalStorage.cxx b/src/storage/plugins/LocalStorage.cxx index 484c9c6db..d1584a316 100644 --- a/src/storage/plugins/LocalStorage.cxx +++ b/src/storage/plugins/LocalStorage.cxx @@ -23,7 +23,7 @@ #include "storage/StorageInterface.hxx" #include "storage/FileInfo.hxx" #include "util/Error.hxx" -#include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "fs/AllocatedPath.hxx" #include "fs/DirectoryReader.hxx" @@ -81,26 +81,25 @@ private: static bool Stat(Path path, bool follow, StorageFileInfo &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()); + FileInfo src; + if (!GetFileInfo(path, src, follow, error)) return false; - } - if (S_ISREG(st.st_mode)) + if (src.IsRegular()) info.type = StorageFileInfo::Type::REGULAR; - else if (S_ISDIR(st.st_mode)) + else if (src.IsDirectory()) info.type = StorageFileInfo::Type::DIRECTORY; else info.type = StorageFileInfo::Type::OTHER; - info.size = st.st_size; - info.mtime = st.st_mtime; - info.device = st.st_dev; - info.inode = st.st_ino; + info.size = src.GetSize(); + info.mtime = src.GetModificationTime(); +#ifdef WIN32 + info.device = info.inode = 0; +#else + info.device = src.GetDevice(); + info.inode = src.GetInode(); +#endif return true; } |