Path: new class "Path" wraps filesystem path strings
This commit is contained in:
parent
8901514506
commit
e5039c478a
@ -26,6 +26,7 @@
|
|||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "mpd_error.h"
|
#include "mpd_error.h"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
#include "decoder_api.h"
|
#include "decoder_api.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "input_stream.h"
|
#include "input_stream.h"
|
||||||
@ -431,7 +432,7 @@ decoder_run(struct decoder_control *dc)
|
|||||||
assert(song != NULL);
|
assert(song != NULL);
|
||||||
|
|
||||||
if (song_is_file(song))
|
if (song_is_file(song))
|
||||||
uri = map_song_fs(song);
|
uri = map_song_fs(song).Steal();
|
||||||
else
|
else
|
||||||
uri = song_get_uri(song);
|
uri = song_get_uri(song);
|
||||||
|
|
||||||
|
@ -32,14 +32,12 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ExcludeList::LoadFile(const char *path_fs)
|
ExcludeList::LoadFile(const Path &path_fs)
|
||||||
{
|
{
|
||||||
assert(path_fs != NULL);
|
FILE *file = fopen(path_fs.c_str(), "r");
|
||||||
|
|
||||||
FILE *file = fopen(path_fs, "r");
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
if (errno != ENOENT) {
|
if (errno != ENOENT) {
|
||||||
char *path_utf8 = fs_charset_to_utf8(path_fs);
|
char *path_utf8 = path_fs.ToUTF8();
|
||||||
g_debug("Failed to open %s: %s",
|
g_debug("Failed to open %s: %s",
|
||||||
path_utf8, g_strerror(errno));
|
path_utf8, g_strerror(errno));
|
||||||
g_free(path_utf8);
|
g_free(path_utf8);
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
class Path;
|
||||||
|
|
||||||
class ExcludeList {
|
class ExcludeList {
|
||||||
class Pattern {
|
class Pattern {
|
||||||
GPatternSpec *pattern;
|
GPatternSpec *pattern;
|
||||||
@ -65,7 +67,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Loads and parses a .mpdignore file.
|
* Loads and parses a .mpdignore file.
|
||||||
*/
|
*/
|
||||||
bool LoadFile(const char *path_fs);
|
bool LoadFile(const Path &path_fs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether one of the patterns in the .mpdignore file matches
|
* Checks whether one of the patterns in the .mpdignore file matches
|
||||||
|
@ -238,7 +238,8 @@ glue_state_file_init(GError **error_r)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
state_file = new StateFile(path, *global_partition, *main_loop);
|
state_file = new StateFile(Path::FromUTF8(path),
|
||||||
|
*global_partition, *main_loop);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
state_file->Read();
|
state_file->Read();
|
||||||
return true;
|
return true;
|
||||||
|
@ -156,67 +156,54 @@ map_to_relative_path(const char *path_utf8)
|
|||||||
: path_utf8;
|
: path_utf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
Path
|
||||||
map_uri_fs(const char *uri)
|
map_uri_fs(const char *uri)
|
||||||
{
|
{
|
||||||
char *uri_fs, *path_fs;
|
|
||||||
|
|
||||||
assert(uri != NULL);
|
assert(uri != NULL);
|
||||||
assert(*uri != '/');
|
assert(*uri != '/');
|
||||||
|
|
||||||
if (music_dir_fs == NULL)
|
if (music_dir_fs == NULL)
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
uri_fs = utf8_to_fs_charset(uri);
|
const Path uri_fs = Path::FromUTF8(uri);
|
||||||
if (uri_fs == NULL)
|
if (uri_fs.IsNull())
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
path_fs = g_build_filename(music_dir_fs, uri_fs, NULL);
|
return Path::Build(music_dir_fs, uri_fs);
|
||||||
g_free(uri_fs);
|
|
||||||
|
|
||||||
return path_fs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
Path
|
||||||
map_directory_fs(const Directory *directory)
|
map_directory_fs(const Directory *directory)
|
||||||
{
|
{
|
||||||
assert(music_dir_utf8 != NULL);
|
assert(music_dir_utf8 != NULL);
|
||||||
assert(music_dir_fs != NULL);
|
assert(music_dir_fs != NULL);
|
||||||
|
|
||||||
if (directory->IsRoot())
|
if (directory->IsRoot())
|
||||||
return g_strdup(music_dir_fs);
|
return Path::FromFS(music_dir_fs);
|
||||||
|
|
||||||
return map_uri_fs(directory->GetPath());
|
return map_uri_fs(directory->GetPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
Path
|
||||||
map_directory_child_fs(const Directory *directory, const char *name)
|
map_directory_child_fs(const Directory *directory, const char *name)
|
||||||
{
|
{
|
||||||
assert(music_dir_utf8 != NULL);
|
assert(music_dir_utf8 != NULL);
|
||||||
assert(music_dir_fs != NULL);
|
assert(music_dir_fs != NULL);
|
||||||
|
|
||||||
char *name_fs, *parent_fs, *path;
|
|
||||||
|
|
||||||
/* check for invalid or unauthorized base names */
|
/* check for invalid or unauthorized base names */
|
||||||
if (*name == 0 || strchr(name, '/') != NULL ||
|
if (*name == 0 || strchr(name, '/') != NULL ||
|
||||||
strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
|
strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
parent_fs = map_directory_fs(directory);
|
const Path parent_fs = map_directory_fs(directory);
|
||||||
if (parent_fs == NULL)
|
if (parent_fs.IsNull())
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
name_fs = utf8_to_fs_charset(name);
|
const Path name_fs = Path::FromUTF8(name);
|
||||||
if (name_fs == NULL) {
|
if (name_fs.IsNull())
|
||||||
g_free(parent_fs);
|
return Path::Null();
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
path = g_build_filename(parent_fs, name_fs, NULL);
|
return Path::Build(parent_fs, name_fs);
|
||||||
g_free(parent_fs);
|
|
||||||
g_free(name_fs);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,19 +211,17 @@ map_directory_child_fs(const Directory *directory, const char *name)
|
|||||||
* not have a real parent directory, only the dummy object
|
* not have a real parent directory, only the dummy object
|
||||||
* #detached_root.
|
* #detached_root.
|
||||||
*/
|
*/
|
||||||
static char *
|
static Path
|
||||||
map_detached_song_fs(const char *uri_utf8)
|
map_detached_song_fs(const char *uri_utf8)
|
||||||
{
|
{
|
||||||
char *uri_fs = utf8_to_fs_charset(uri_utf8);
|
Path uri_fs = Path::FromUTF8(uri_utf8);
|
||||||
if (uri_fs == NULL)
|
if (uri_fs.IsNull())
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
char *path = g_build_filename(music_dir_fs, uri_fs, NULL);
|
return Path::Build(music_dir_fs, uri_fs);
|
||||||
g_free(uri_fs);
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
Path
|
||||||
map_song_fs(const struct song *song)
|
map_song_fs(const struct song *song)
|
||||||
{
|
{
|
||||||
assert(song_is_file(song));
|
assert(song_is_file(song));
|
||||||
@ -246,7 +231,7 @@ map_song_fs(const struct song *song)
|
|||||||
? map_detached_song_fs(song->uri)
|
? map_detached_song_fs(song->uri)
|
||||||
: map_directory_child_fs(song->parent, song->uri);
|
: map_directory_child_fs(song->parent, song->uri);
|
||||||
else
|
else
|
||||||
return utf8_to_fs_charset(song->uri);
|
return Path::FromUTF8(song->uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
@ -273,22 +258,17 @@ map_spl_path(void)
|
|||||||
return playlist_dir_fs;
|
return playlist_dir_fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
Path
|
||||||
map_spl_utf8_to_fs(const char *name)
|
map_spl_utf8_to_fs(const char *name)
|
||||||
{
|
{
|
||||||
char *filename_utf8, *filename_fs, *path;
|
|
||||||
|
|
||||||
if (playlist_dir_fs == NULL)
|
if (playlist_dir_fs == NULL)
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
filename_utf8 = g_strconcat(name, PLAYLIST_FILE_SUFFIX, NULL);
|
char *filename_utf8 = g_strconcat(name, PLAYLIST_FILE_SUFFIX, NULL);
|
||||||
filename_fs = utf8_to_fs_charset(filename_utf8);
|
const Path filename_fs = Path::FromUTF8(filename_utf8);
|
||||||
g_free(filename_utf8);
|
g_free(filename_utf8);
|
||||||
if (filename_fs == NULL)
|
if (filename_fs.IsNull())
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
path = g_build_filename(playlist_dir_fs, filename_fs, NULL);
|
return Path::Build(playlist_dir_fs, filename_fs);
|
||||||
g_free(filename_fs);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#define PLAYLIST_FILE_SUFFIX ".m3u"
|
#define PLAYLIST_FILE_SUFFIX ".m3u"
|
||||||
|
|
||||||
|
class Path;
|
||||||
struct Directory;
|
struct Directory;
|
||||||
struct song;
|
struct song;
|
||||||
|
|
||||||
@ -75,8 +76,8 @@ map_to_relative_path(const char *path_utf8);
|
|||||||
* is basically done by converting the URI to the file system charset
|
* is basically done by converting the URI to the file system charset
|
||||||
* and prepending the music directory.
|
* and prepending the music directory.
|
||||||
*/
|
*/
|
||||||
gcc_malloc
|
gcc_pure
|
||||||
char *
|
Path
|
||||||
map_uri_fs(const char *uri);
|
map_uri_fs(const char *uri);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,8 +86,8 @@ map_uri_fs(const char *uri);
|
|||||||
* @param directory the directory object
|
* @param directory the directory object
|
||||||
* @return the path in file system encoding, or nullptr if mapping failed
|
* @return the path in file system encoding, or nullptr if mapping failed
|
||||||
*/
|
*/
|
||||||
gcc_malloc
|
gcc_pure
|
||||||
char *
|
Path
|
||||||
map_directory_fs(const Directory *directory);
|
map_directory_fs(const Directory *directory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,8 +98,8 @@ map_directory_fs(const Directory *directory);
|
|||||||
* @param name the child's name in UTF-8
|
* @param name the child's name in UTF-8
|
||||||
* @return the path in file system encoding, or nullptr if mapping failed
|
* @return the path in file system encoding, or nullptr if mapping failed
|
||||||
*/
|
*/
|
||||||
gcc_malloc
|
gcc_pure
|
||||||
char *
|
Path
|
||||||
map_directory_child_fs(const Directory *directory, const char *name);
|
map_directory_child_fs(const Directory *directory, const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,8 +109,8 @@ map_directory_child_fs(const Directory *directory, const char *name);
|
|||||||
* @param song the song object
|
* @param song the song object
|
||||||
* @return the path in file system encoding, or nullptr if mapping failed
|
* @return the path in file system encoding, or nullptr if mapping failed
|
||||||
*/
|
*/
|
||||||
gcc_malloc
|
gcc_pure
|
||||||
char *
|
Path
|
||||||
map_song_fs(const struct song *song);
|
map_song_fs(const struct song *song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,7 +139,7 @@ map_spl_path(void);
|
|||||||
* @return the path in file system encoding, or nullptr if mapping failed
|
* @return the path in file system encoding, or nullptr if mapping failed
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
char *
|
Path
|
||||||
map_spl_utf8_to_fs(const char *name);
|
map_spl_utf8_to_fs(const char *name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
207
src/Path.hxx
207
src/Path.hxx
@ -21,7 +21,14 @@
|
|||||||
#define MPD_PATH_HXX
|
#define MPD_PATH_HXX
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "gcc.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#if !defined(MPD_PATH_MAX)
|
#if !defined(MPD_PATH_MAX)
|
||||||
@ -54,4 +61,204 @@ utf8_to_fs_charset(const char *path_utf8);
|
|||||||
|
|
||||||
const char *path_get_fs_charset();
|
const char *path_get_fs_charset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A path name in the native file system character set.
|
||||||
|
*/
|
||||||
|
class Path {
|
||||||
|
public:
|
||||||
|
typedef char value_type;
|
||||||
|
typedef value_type *pointer;
|
||||||
|
typedef const value_type *const_pointer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
pointer value;
|
||||||
|
|
||||||
|
struct Donate {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Donate the allocated pointer to a new #Path object.
|
||||||
|
*/
|
||||||
|
constexpr Path(Donate, pointer _value):value(_value) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release memory allocated by the value, but do not clear the
|
||||||
|
* value pointer.
|
||||||
|
*/
|
||||||
|
void Free() {
|
||||||
|
/* free() can be optimized by gcc, while g_free() can
|
||||||
|
not: when the compiler knows that the value is
|
||||||
|
nullptr, it will not emit a free() call in the
|
||||||
|
inlined destructor; however on Windows, we need to
|
||||||
|
call g_free(), because the value has been allocated
|
||||||
|
by GLib, and on Windows, this matters */
|
||||||
|
#ifdef WIN32
|
||||||
|
g_free(value);
|
||||||
|
#else
|
||||||
|
free(value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Copy a #Path object.
|
||||||
|
*/
|
||||||
|
Path(const Path &other)
|
||||||
|
:value(g_strdup(other.value)) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a #Path object.
|
||||||
|
*/
|
||||||
|
Path(Path &&other):value(other.value) {
|
||||||
|
other.value = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Path() {
|
||||||
|
Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a "nulled" instance. Its IsNull() method will
|
||||||
|
* return true. Such an object must not be used.
|
||||||
|
*
|
||||||
|
* @see IsNull()
|
||||||
|
*/
|
||||||
|
gcc_const
|
||||||
|
static Path Null() {
|
||||||
|
return Path(Donate(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join two path components with the path separator.
|
||||||
|
*/
|
||||||
|
gcc_pure gcc_nonnull_all
|
||||||
|
static Path Build(const_pointer a, const_pointer b) {
|
||||||
|
return Path(Donate(), g_build_filename(a, b, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure gcc_nonnull_all
|
||||||
|
static Path Build(const_pointer a, const Path &b) {
|
||||||
|
return Build(a, b.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure gcc_nonnull_all
|
||||||
|
static Path Build(const Path &a, const_pointer b) {
|
||||||
|
return Build(a.c_str(), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
static Path Build(const Path &a, const Path &b) {
|
||||||
|
return Build(a.c_str(), b.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a C string that is already in the filesystem
|
||||||
|
* character set to a #Path instance.
|
||||||
|
*/
|
||||||
|
gcc_pure
|
||||||
|
static Path FromFS(const_pointer fs) {
|
||||||
|
return Path(Donate(), g_strdup(fs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a UTF-8 C string to a #Path instance.
|
||||||
|
*
|
||||||
|
* TODO: return a "nulled" instance on error and add checks to
|
||||||
|
* all callers
|
||||||
|
*/
|
||||||
|
gcc_pure
|
||||||
|
static Path FromUTF8(const char *utf8) {
|
||||||
|
return Path(Donate(), utf8_to_fs_charset(utf8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a #Path object.
|
||||||
|
*/
|
||||||
|
Path &operator=(const Path &other) {
|
||||||
|
if (this != &other) {
|
||||||
|
Free();
|
||||||
|
value = g_strdup(other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a #Path object.
|
||||||
|
*/
|
||||||
|
Path &operator=(Path &&other) {
|
||||||
|
std::swap(value, other.value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steal the allocated value. This object has an undefined
|
||||||
|
* value, and the caller is response for freeing this method's
|
||||||
|
* return value.
|
||||||
|
*/
|
||||||
|
pointer Steal() {
|
||||||
|
pointer result = value;
|
||||||
|
value = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this is a "nulled" instance. A "nulled" instance
|
||||||
|
* must not be used.
|
||||||
|
*/
|
||||||
|
bool IsNull() const {
|
||||||
|
return value == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear this object's value, make it "nulled".
|
||||||
|
*
|
||||||
|
* @see IsNull()
|
||||||
|
*/
|
||||||
|
void SetNull() {
|
||||||
|
Free();
|
||||||
|
value = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool empty() const {
|
||||||
|
assert(value != nullptr);
|
||||||
|
|
||||||
|
return *value == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the length of this string in number of "value_type"
|
||||||
|
* elements (which may not be the number of characters).
|
||||||
|
*/
|
||||||
|
gcc_pure
|
||||||
|
size_t length() const {
|
||||||
|
assert(value != nullptr);
|
||||||
|
|
||||||
|
return strlen(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value as a const C string. The returned
|
||||||
|
* pointer is invalidated whenever the value of life of this
|
||||||
|
* instance ends.
|
||||||
|
*/
|
||||||
|
gcc_pure
|
||||||
|
const_pointer c_str() const {
|
||||||
|
assert(value != nullptr);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the path to UTF-8. The caller is responsible for
|
||||||
|
* freeing the return value with g_free(). Returns nullptr on
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
char *ToUTF8() const {
|
||||||
|
return value != nullptr
|
||||||
|
? fs_charset_to_utf8(value)
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,15 +106,15 @@ spl_check_name(const char *name_utf8, GError **error_r)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static Path
|
||||||
spl_map_to_fs(const char *name_utf8, GError **error_r)
|
spl_map_to_fs(const char *name_utf8, GError **error_r)
|
||||||
{
|
{
|
||||||
if (spl_map(error_r) == NULL ||
|
if (spl_map(error_r) == NULL ||
|
||||||
!spl_check_name(name_utf8, error_r))
|
!spl_check_name(name_utf8, error_r))
|
||||||
return NULL;
|
return Path::Null();
|
||||||
|
|
||||||
char *path_fs = map_spl_utf8_to_fs(name_utf8);
|
Path path_fs = map_spl_utf8_to_fs(name_utf8);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
g_set_error_literal(error_r, playlist_quark(),
|
g_set_error_literal(error_r, playlist_quark(),
|
||||||
PLAYLIST_RESULT_BAD_NAME,
|
PLAYLIST_RESULT_BAD_NAME,
|
||||||
"Bad playlist name");
|
"Bad playlist name");
|
||||||
@ -209,12 +209,11 @@ SavePlaylistFile(const PlaylistFileContents &contents, const char *utf8path,
|
|||||||
if (spl_map(error_r) == NULL)
|
if (spl_map(error_r) == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char *path_fs = spl_map_to_fs(utf8path, error_r);
|
const Path path_fs = spl_map_to_fs(utf8path, error_r);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FILE *file = fopen(path_fs, "w");
|
FILE *file = fopen(path_fs.c_str(), "w");
|
||||||
g_free(path_fs);
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
playlist_errno(error_r);
|
playlist_errno(error_r);
|
||||||
return false;
|
return false;
|
||||||
@ -235,8 +234,8 @@ LoadPlaylistFile(const char *utf8path, GError **error_r)
|
|||||||
if (spl_map(error_r) == NULL)
|
if (spl_map(error_r) == NULL)
|
||||||
return contents;
|
return contents;
|
||||||
|
|
||||||
char *path_fs = spl_map_to_fs(utf8path, error_r);
|
const Path path_fs = spl_map_to_fs(utf8path, error_r);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return contents;
|
return contents;
|
||||||
|
|
||||||
TextFile file(path_fs);
|
TextFile file(path_fs);
|
||||||
@ -308,17 +307,14 @@ spl_move_index(const char *utf8path, unsigned src, unsigned dest,
|
|||||||
bool
|
bool
|
||||||
spl_clear(const char *utf8path, GError **error_r)
|
spl_clear(const char *utf8path, GError **error_r)
|
||||||
{
|
{
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
if (spl_map(error_r) == NULL)
|
if (spl_map(error_r) == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char *path_fs = spl_map_to_fs(utf8path, error_r);
|
const Path path_fs = spl_map_to_fs(utf8path, error_r);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
file = fopen(path_fs, "w");
|
FILE *file = fopen(path_fs.c_str(), "w");
|
||||||
g_free(path_fs);
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
playlist_errno(error_r);
|
playlist_errno(error_r);
|
||||||
return false;
|
return false;
|
||||||
@ -333,12 +329,11 @@ spl_clear(const char *utf8path, GError **error_r)
|
|||||||
bool
|
bool
|
||||||
spl_delete(const char *name_utf8, GError **error_r)
|
spl_delete(const char *name_utf8, GError **error_r)
|
||||||
{
|
{
|
||||||
char *path_fs = spl_map_to_fs(name_utf8, error_r);
|
const Path path_fs = spl_map_to_fs(name_utf8, error_r);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int ret = unlink(path_fs);
|
int ret = unlink(path_fs.c_str());
|
||||||
g_free(path_fs);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
playlist_errno(error_r);
|
playlist_errno(error_r);
|
||||||
return false;
|
return false;
|
||||||
@ -376,17 +371,14 @@ spl_remove_index(const char *utf8path, unsigned pos, GError **error_r)
|
|||||||
bool
|
bool
|
||||||
spl_append_song(const char *utf8path, struct song *song, GError **error_r)
|
spl_append_song(const char *utf8path, struct song *song, GError **error_r)
|
||||||
{
|
{
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
if (spl_map(error_r) == NULL)
|
if (spl_map(error_r) == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char *path_fs = spl_map_to_fs(utf8path, error_r);
|
const Path path_fs = spl_map_to_fs(utf8path, error_r);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
file = fopen(path_fs, "a");
|
FILE *file = fopen(path_fs.c_str(), "a");
|
||||||
g_free(path_fs);
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
playlist_errno(error_r);
|
playlist_errno(error_r);
|
||||||
return false;
|
return false;
|
||||||
@ -439,24 +431,24 @@ spl_append_uri(const char *url, const char *utf8file, GError **error_r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
spl_rename_internal(const char *from_path_fs, const char *to_path_fs,
|
spl_rename_internal(const Path &from_path_fs, const Path &to_path_fs,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
if (!g_file_test(from_path_fs, G_FILE_TEST_IS_REGULAR)) {
|
if (!g_file_test(from_path_fs.c_str(), G_FILE_TEST_IS_REGULAR)) {
|
||||||
g_set_error_literal(error_r, playlist_quark(),
|
g_set_error_literal(error_r, playlist_quark(),
|
||||||
PLAYLIST_RESULT_NO_SUCH_LIST,
|
PLAYLIST_RESULT_NO_SUCH_LIST,
|
||||||
"No such playlist");
|
"No such playlist");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_file_test(to_path_fs, G_FILE_TEST_EXISTS)) {
|
if (g_file_test(to_path_fs.c_str(), G_FILE_TEST_EXISTS)) {
|
||||||
g_set_error_literal(error_r, playlist_quark(),
|
g_set_error_literal(error_r, playlist_quark(),
|
||||||
PLAYLIST_RESULT_LIST_EXISTS,
|
PLAYLIST_RESULT_LIST_EXISTS,
|
||||||
"Playlist exists already");
|
"Playlist exists already");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rename(from_path_fs, to_path_fs) < 0) {
|
if (rename(from_path_fs.c_str(), to_path_fs.c_str()) < 0) {
|
||||||
playlist_errno(error_r);
|
playlist_errno(error_r);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -471,20 +463,13 @@ spl_rename(const char *utf8from, const char *utf8to, GError **error_r)
|
|||||||
if (spl_map(error_r) == NULL)
|
if (spl_map(error_r) == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char *from_path_fs = spl_map_to_fs(utf8from, error_r);
|
Path from_path_fs = spl_map_to_fs(utf8from, error_r);
|
||||||
if (from_path_fs == NULL)
|
if (from_path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char *to_path_fs = spl_map_to_fs(utf8to, error_r);
|
Path to_path_fs = spl_map_to_fs(utf8to, error_r);
|
||||||
if (to_path_fs == NULL) {
|
if (to_path_fs.IsNull())
|
||||||
g_free(from_path_fs);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
return spl_rename_internal(from_path_fs, to_path_fs, error_r);
|
||||||
bool success = spl_rename_internal(from_path_fs, to_path_fs, error_r);
|
|
||||||
|
|
||||||
g_free(from_path_fs);
|
|
||||||
g_free(to_path_fs);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "PlaylistMapper.hxx"
|
#include "PlaylistMapper.hxx"
|
||||||
#include "PlaylistFile.hxx"
|
#include "PlaylistFile.hxx"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "playlist_list.h"
|
#include "playlist_list.h"
|
||||||
@ -75,19 +76,13 @@ static struct playlist_provider *
|
|||||||
playlist_open_in_music_dir(const char *uri, GMutex *mutex, GCond *cond,
|
playlist_open_in_music_dir(const char *uri, GMutex *mutex, GCond *cond,
|
||||||
struct input_stream **is_r)
|
struct input_stream **is_r)
|
||||||
{
|
{
|
||||||
char *path_fs;
|
|
||||||
|
|
||||||
assert(uri_safe_local(uri));
|
assert(uri_safe_local(uri));
|
||||||
|
|
||||||
path_fs = map_uri_fs(uri);
|
Path path = map_uri_fs(uri);
|
||||||
if (path_fs == NULL)
|
if (path.IsNull())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
struct playlist_provider *playlist =
|
return playlist_open_path(path.c_str(), mutex, cond, is_r);
|
||||||
playlist_open_path(path_fs, mutex, cond, is_r);
|
|
||||||
g_free(path_fs);
|
|
||||||
|
|
||||||
return playlist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct playlist_provider *
|
struct playlist_provider *
|
||||||
|
@ -38,62 +38,47 @@ void
|
|||||||
playlist_print_song(FILE *file, const struct song *song)
|
playlist_print_song(FILE *file, const struct song *song)
|
||||||
{
|
{
|
||||||
if (playlist_saveAbsolutePaths && song_in_database(song)) {
|
if (playlist_saveAbsolutePaths && song_in_database(song)) {
|
||||||
char *path = map_song_fs(song);
|
const Path path = map_song_fs(song);
|
||||||
if (path != NULL) {
|
if (!path.IsNull())
|
||||||
fprintf(file, "%s\n", path);
|
fprintf(file, "%s\n", path.c_str());
|
||||||
g_free(path);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
char *uri = song_get_uri(song), *uri_fs;
|
char *uri = song_get_uri(song);
|
||||||
|
const Path uri_fs = Path::FromUTF8(uri);
|
||||||
uri_fs = utf8_to_fs_charset(uri);
|
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
|
||||||
fprintf(file, "%s\n", uri_fs);
|
fprintf(file, "%s\n", uri_fs.c_str());
|
||||||
g_free(uri_fs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_print_uri(FILE *file, const char *uri)
|
playlist_print_uri(FILE *file, const char *uri)
|
||||||
{
|
{
|
||||||
char *s;
|
Path path = playlist_saveAbsolutePaths && !uri_has_scheme(uri) &&
|
||||||
|
!g_path_is_absolute(uri)
|
||||||
|
? map_uri_fs(uri)
|
||||||
|
: Path::FromUTF8(uri);
|
||||||
|
|
||||||
if (playlist_saveAbsolutePaths && !uri_has_scheme(uri) &&
|
if (!path.IsNull())
|
||||||
!g_path_is_absolute(uri))
|
fprintf(file, "%s\n", path.c_str());
|
||||||
s = map_uri_fs(uri);
|
|
||||||
else
|
|
||||||
s = utf8_to_fs_charset(uri);
|
|
||||||
|
|
||||||
if (s != NULL) {
|
|
||||||
fprintf(file, "%s\n", s);
|
|
||||||
g_free(s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
spl_save_queue(const char *name_utf8, const struct queue *queue)
|
spl_save_queue(const char *name_utf8, const struct queue *queue)
|
||||||
{
|
{
|
||||||
char *path_fs;
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
if (map_spl_path() == NULL)
|
if (map_spl_path() == NULL)
|
||||||
return PLAYLIST_RESULT_DISABLED;
|
return PLAYLIST_RESULT_DISABLED;
|
||||||
|
|
||||||
if (!spl_valid_name(name_utf8))
|
if (!spl_valid_name(name_utf8))
|
||||||
return PLAYLIST_RESULT_BAD_NAME;
|
return PLAYLIST_RESULT_BAD_NAME;
|
||||||
|
|
||||||
path_fs = map_spl_utf8_to_fs(name_utf8);
|
const Path path_fs = map_spl_utf8_to_fs(name_utf8);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return PLAYLIST_RESULT_BAD_NAME;
|
return PLAYLIST_RESULT_BAD_NAME;
|
||||||
|
|
||||||
if (g_file_test(path_fs, G_FILE_TEST_EXISTS)) {
|
if (g_file_test(path_fs.c_str(), G_FILE_TEST_EXISTS))
|
||||||
g_free(path_fs);
|
|
||||||
return PLAYLIST_RESULT_LIST_EXISTS;
|
return PLAYLIST_RESULT_LIST_EXISTS;
|
||||||
}
|
|
||||||
|
|
||||||
file = fopen(path_fs, "w");
|
FILE *file = fopen(path_fs.c_str(), "w");
|
||||||
g_free(path_fs);
|
|
||||||
|
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
return PLAYLIST_RESULT_ERRNO;
|
return PLAYLIST_RESULT_ERRNO;
|
||||||
|
@ -65,8 +65,8 @@ apply_song_metadata(struct song *dest, const struct song *src)
|
|||||||
return dest;
|
return dest;
|
||||||
|
|
||||||
if (song_in_database(dest)) {
|
if (song_in_database(dest)) {
|
||||||
char *path_fs = map_song_fs(dest);
|
char *path_fs = map_song_fs(dest).Steal();
|
||||||
if (path_fs == NULL)
|
if (path_fs == nullptr)
|
||||||
return dest;
|
return dest;
|
||||||
|
|
||||||
char *path_utf8 = fs_charset_to_utf8(path_fs);
|
char *path_utf8 = fs_charset_to_utf8(path_fs);
|
||||||
|
@ -26,6 +26,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "input_stream.h"
|
#include "input_stream.h"
|
||||||
|
|
||||||
@ -85,7 +86,6 @@ bool
|
|||||||
song_file_update(struct song *song)
|
song_file_update(struct song *song)
|
||||||
{
|
{
|
||||||
const char *suffix;
|
const char *suffix;
|
||||||
char *path_fs;
|
|
||||||
const struct decoder_plugin *plugin;
|
const struct decoder_plugin *plugin;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct input_stream *is = NULL;
|
struct input_stream *is = NULL;
|
||||||
@ -102,8 +102,8 @@ song_file_update(struct song *song)
|
|||||||
if (plugin == NULL)
|
if (plugin == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
path_fs = map_song_fs(song);
|
const Path path_fs = map_song_fs(song);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (song->tag != NULL) {
|
if (song->tag != NULL) {
|
||||||
@ -111,8 +111,7 @@ song_file_update(struct song *song)
|
|||||||
song->tag = NULL;
|
song->tag = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
|
if (stat(path_fs.c_str(), &st) < 0 || !S_ISREG(st.st_mode)) {
|
||||||
g_free(path_fs);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +128,7 @@ song_file_update(struct song *song)
|
|||||||
do {
|
do {
|
||||||
/* load file tag */
|
/* load file tag */
|
||||||
song->tag = tag_new();
|
song->tag = tag_new();
|
||||||
if (decoder_plugin_scan_file(plugin, path_fs,
|
if (decoder_plugin_scan_file(plugin, path_fs.c_str(),
|
||||||
&full_tag_handler, song->tag))
|
&full_tag_handler, song->tag))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -143,7 +142,8 @@ song_file_update(struct song *song)
|
|||||||
if (is == NULL) {
|
if (is == NULL) {
|
||||||
mutex = g_mutex_new();
|
mutex = g_mutex_new();
|
||||||
cond = g_cond_new();
|
cond = g_cond_new();
|
||||||
is = input_stream_open(path_fs, mutex, cond,
|
is = input_stream_open(path_fs.c_str(),
|
||||||
|
mutex, cond,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,9 +174,9 @@ song_file_update(struct song *song)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (song->tag != NULL && tag_is_empty(song->tag))
|
if (song->tag != NULL && tag_is_empty(song->tag))
|
||||||
tag_scan_fallback(path_fs, &full_tag_handler, song->tag);
|
tag_scan_fallback(path_fs.c_str(), &full_tag_handler,
|
||||||
|
song->tag);
|
||||||
|
|
||||||
g_free(path_fs);
|
|
||||||
return song->tag != NULL;
|
return song->tag != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@
|
|||||||
#undef G_LOG_DOMAIN
|
#undef G_LOG_DOMAIN
|
||||||
#define G_LOG_DOMAIN "state_file"
|
#define G_LOG_DOMAIN "state_file"
|
||||||
|
|
||||||
StateFile::StateFile(const char *_path, Partition &_partition, EventLoop &_loop)
|
StateFile::StateFile(Path &&_path, Partition &_partition, EventLoop &_loop)
|
||||||
:TimeoutMonitor(_loop), path(_path), partition(_partition),
|
:TimeoutMonitor(_loop), path(std::move(_path)), partition(_partition),
|
||||||
prev_volume_version(0), prev_output_version(0),
|
prev_volume_version(0), prev_output_version(0),
|
||||||
prev_playlist_version(0)
|
prev_playlist_version(0)
|
||||||
{
|
{
|
||||||
@ -73,7 +73,7 @@ StateFile::Read()
|
|||||||
|
|
||||||
g_debug("Loading state file %s", path.c_str());
|
g_debug("Loading state file %s", path.c_str());
|
||||||
|
|
||||||
TextFile file(path.c_str());
|
TextFile file(path);
|
||||||
if (file.HasFailed()) {
|
if (file.HasFailed()) {
|
||||||
g_warning("failed to open %s: %s",
|
g_warning("failed to open %s: %s",
|
||||||
path.c_str(), g_strerror(errno));
|
path.c_str(), g_strerror(errno));
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define MPD_STATE_FILE_HXX
|
#define MPD_STATE_FILE_HXX
|
||||||
|
|
||||||
#include "event/TimeoutMonitor.hxx"
|
#include "event/TimeoutMonitor.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
#include "gcc.h"
|
#include "gcc.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -28,7 +29,7 @@
|
|||||||
struct Partition;
|
struct Partition;
|
||||||
|
|
||||||
class StateFile final : private TimeoutMonitor {
|
class StateFile final : private TimeoutMonitor {
|
||||||
std::string path;
|
Path path;
|
||||||
|
|
||||||
Partition &partition;
|
Partition &partition;
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ class StateFile final : private TimeoutMonitor {
|
|||||||
prev_playlist_version;
|
prev_playlist_version;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StateFile(const char *path, Partition &partition, EventLoop &loop);
|
StateFile(Path &&path, Partition &partition, EventLoop &loop);
|
||||||
|
|
||||||
void Read();
|
void Read();
|
||||||
void Write();
|
void Write();
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define MPD_TEXT_FILE_HXX
|
#define MPD_TEXT_FILE_HXX
|
||||||
|
|
||||||
#include "gcc.h"
|
#include "gcc.h"
|
||||||
|
#include "Path.hxx"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
@ -35,8 +36,9 @@ class TextFile {
|
|||||||
GString *const buffer;
|
GString *const buffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TextFile(const char *path_fs)
|
TextFile(const Path &path_fs)
|
||||||
:file(fopen(path_fs, "r")), buffer(g_string_sized_new(step)) {}
|
:file(fopen(path_fs.c_str(), "r")),
|
||||||
|
buffer(g_string_sized_new(step)) {}
|
||||||
|
|
||||||
TextFile(const TextFile &other) = delete;
|
TextFile(const TextFile &other) = delete;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "archive_list.h"
|
#include "archive_list.h"
|
||||||
@ -96,20 +97,19 @@ update_archive_file2(Directory *parent, const char *name,
|
|||||||
changed since - don't consider updating it */
|
changed since - don't consider updating it */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char *path_fs = map_directory_child_fs(parent, name);
|
const Path path_fs = map_directory_child_fs(parent, name);
|
||||||
|
|
||||||
/* open archive */
|
/* open archive */
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
struct archive_file *file = archive_file_open(plugin, path_fs, &error);
|
struct archive_file *file = archive_file_open(plugin, path_fs.c_str(),
|
||||||
|
&error);
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
g_free(path_fs);
|
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_debug("archive %s opened", path_fs);
|
g_debug("archive %s opened", path_fs.c_str());
|
||||||
g_free(path_fs);
|
|
||||||
|
|
||||||
if (directory == NULL) {
|
if (directory == NULL) {
|
||||||
g_debug("creating archive directory: %s", name);
|
g_debug("creating archive directory: %s", name);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "decoder_plugin.h"
|
#include "decoder_plugin.h"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "tag_handler.h"
|
#include "tag_handler.h"
|
||||||
@ -84,22 +85,22 @@ update_container_file(Directory *directory,
|
|||||||
contdir->device = DEVICE_CONTAINER;
|
contdir->device = DEVICE_CONTAINER;
|
||||||
db_unlock();
|
db_unlock();
|
||||||
|
|
||||||
char *const pathname = map_directory_child_fs(directory, name);
|
const Path pathname = map_directory_child_fs(directory, name);
|
||||||
|
|
||||||
char *vtrack;
|
char *vtrack;
|
||||||
unsigned int tnum = 0;
|
unsigned int tnum = 0;
|
||||||
while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL) {
|
while ((vtrack = plugin->container_scan(pathname.c_str(), ++tnum)) != NULL) {
|
||||||
struct song *song = song_file_new(vtrack, contdir);
|
struct song *song = song_file_new(vtrack, contdir);
|
||||||
|
|
||||||
// shouldn't be necessary but it's there..
|
// shouldn't be necessary but it's there..
|
||||||
song->mtime = st->st_mtime;
|
song->mtime = st->st_mtime;
|
||||||
|
|
||||||
char *child_path_fs = map_directory_child_fs(contdir, vtrack);
|
const Path child_path_fs =
|
||||||
|
map_directory_child_fs(contdir, vtrack);
|
||||||
|
|
||||||
song->tag = tag_new();
|
song->tag = tag_new();
|
||||||
decoder_plugin_scan_file(plugin, child_path_fs,
|
decoder_plugin_scan_file(plugin, child_path_fs.c_str(),
|
||||||
&add_tag_handler, song->tag);
|
&add_tag_handler, song->tag);
|
||||||
g_free(child_path_fs);
|
|
||||||
|
|
||||||
db_lock();
|
db_lock();
|
||||||
contdir->AddSong(song);
|
contdir->AddSong(song);
|
||||||
@ -111,8 +112,6 @@ update_container_file(Directory *directory,
|
|||||||
g_free(vtrack);
|
g_free(vtrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(pathname);
|
|
||||||
|
|
||||||
if (tnum == 1) {
|
if (tnum == 1) {
|
||||||
db_lock();
|
db_lock();
|
||||||
delete_directory(contdir);
|
delete_directory(contdir);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "UpdateIO.hxx"
|
#include "UpdateIO.hxx"
|
||||||
#include "Directory.hxx"
|
#include "Directory.hxx"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
#include "glib_compat.h"
|
#include "glib_compat.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@ -31,15 +32,15 @@
|
|||||||
int
|
int
|
||||||
stat_directory(const Directory *directory, struct stat *st)
|
stat_directory(const Directory *directory, struct stat *st)
|
||||||
{
|
{
|
||||||
char *path_fs = map_directory_fs(directory);
|
const Path path_fs = map_directory_fs(directory);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int ret = stat(path_fs, st);
|
int ret = stat(path_fs.c_str(), st);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
g_warning("Failed to stat %s: %s", path_fs, g_strerror(errno));
|
g_warning("Failed to stat %s: %s",
|
||||||
|
path_fs.c_str(), g_strerror(errno));
|
||||||
|
|
||||||
g_free(path_fs);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,23 +48,23 @@ int
|
|||||||
stat_directory_child(const Directory *parent, const char *name,
|
stat_directory_child(const Directory *parent, const char *name,
|
||||||
struct stat *st)
|
struct stat *st)
|
||||||
{
|
{
|
||||||
char *path_fs = map_directory_child_fs(parent, name);
|
const Path path_fs = map_directory_child_fs(parent, name);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int ret = stat(path_fs, st);
|
int ret = stat(path_fs.c_str(), st);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
g_warning("Failed to stat %s: %s", path_fs, g_strerror(errno));
|
g_warning("Failed to stat %s: %s",
|
||||||
|
path_fs.c_str(), g_strerror(errno));
|
||||||
|
|
||||||
g_free(path_fs);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
directory_exists(const Directory *directory)
|
directory_exists(const Directory *directory)
|
||||||
{
|
{
|
||||||
char *path_fs = map_directory_fs(directory);
|
const Path path_fs = map_directory_fs(directory);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
/* invalid path: cannot exist */
|
/* invalid path: cannot exist */
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -72,25 +73,19 @@ directory_exists(const Directory *directory)
|
|||||||
? G_FILE_TEST_IS_REGULAR
|
? G_FILE_TEST_IS_REGULAR
|
||||||
: G_FILE_TEST_IS_DIR;
|
: G_FILE_TEST_IS_DIR;
|
||||||
|
|
||||||
bool exists = g_file_test(path_fs, test);
|
return g_file_test(path_fs.c_str(), test);
|
||||||
g_free(path_fs);
|
|
||||||
|
|
||||||
return exists;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
directory_child_is_regular(const Directory *directory,
|
directory_child_is_regular(const Directory *directory,
|
||||||
const char *name_utf8)
|
const char *name_utf8)
|
||||||
{
|
{
|
||||||
char *path_fs = map_directory_child_fs(directory, name_utf8);
|
const Path path_fs = map_directory_child_fs(directory, name_utf8);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
bool is_regular = stat(path_fs, &st) == 0 && S_ISREG(st.st_mode);
|
return stat(path_fs.c_str(), &st) == 0 && S_ISREG(st.st_mode);
|
||||||
g_free(path_fs);
|
|
||||||
|
|
||||||
return is_regular;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -104,14 +99,12 @@ directory_child_access(const Directory *directory,
|
|||||||
(void)mode;
|
(void)mode;
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
char *path = map_directory_child_fs(directory, name);
|
const Path path = map_directory_child_fs(directory, name);
|
||||||
if (path == NULL)
|
if (path.IsNull())
|
||||||
/* something went wrong, but that isn't a permission
|
/* something went wrong, but that isn't a permission
|
||||||
problem */
|
problem */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool success = access(path, mode) == 0 || errno != EACCES;
|
return access(path.c_str(), mode) == 0 || errno != EACCES;
|
||||||
g_free(path);
|
|
||||||
return success;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -102,27 +102,23 @@ remove_excluded_from_directory(Directory *directory,
|
|||||||
|
|
||||||
Directory *child, *n;
|
Directory *child, *n;
|
||||||
directory_for_each_child_safe(child, n, directory) {
|
directory_for_each_child_safe(child, n, directory) {
|
||||||
char *name_fs = utf8_to_fs_charset(child->GetName());
|
const Path name_fs = Path::FromUTF8(child->GetName());
|
||||||
|
|
||||||
if (exclude_list.Check(name_fs)) {
|
if (exclude_list.Check(name_fs.c_str())) {
|
||||||
delete_directory(child);
|
delete_directory(child);
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(name_fs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct song *song, *ns;
|
struct song *song, *ns;
|
||||||
directory_for_each_song_safe(song, ns, directory) {
|
directory_for_each_song_safe(song, ns, directory) {
|
||||||
assert(song->parent == directory);
|
assert(song->parent == directory);
|
||||||
|
|
||||||
char *name_fs = utf8_to_fs_charset(song->uri);
|
const Path name_fs = Path::FromUTF8(song->uri);
|
||||||
if (exclude_list.Check(name_fs)) {
|
if (exclude_list.Check(name_fs.c_str())) {
|
||||||
delete_song(directory, song);
|
delete_song(directory, song);
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(name_fs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db_unlock();
|
db_unlock();
|
||||||
@ -145,18 +141,16 @@ purge_deleted_from_directory(Directory *directory)
|
|||||||
|
|
||||||
struct song *song, *ns;
|
struct song *song, *ns;
|
||||||
directory_for_each_song_safe(song, ns, directory) {
|
directory_for_each_song_safe(song, ns, directory) {
|
||||||
char *path;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if ((path = map_song_fs(song)) == NULL ||
|
const Path path = map_song_fs(song);
|
||||||
stat(path, &st) < 0 || !S_ISREG(st.st_mode)) {
|
if (path.IsNull() ||
|
||||||
|
stat(path.c_str(), &st) < 0 || !S_ISREG(st.st_mode)) {
|
||||||
db_lock();
|
db_lock();
|
||||||
delete_song(directory, song);
|
delete_song(directory, song);
|
||||||
db_unlock();
|
db_unlock();
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i = directory->playlists.begin(),
|
for (auto i = directory->playlists.begin(),
|
||||||
@ -283,13 +277,12 @@ static bool
|
|||||||
skip_symlink(const Directory *directory, const char *utf8_name)
|
skip_symlink(const Directory *directory, const char *utf8_name)
|
||||||
{
|
{
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
char *path_fs = map_directory_child_fs(directory, utf8_name);
|
const Path path_fs = map_directory_child_fs(directory, utf8_name);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
char buffer[MPD_PATH_MAX];
|
char buffer[MPD_PATH_MAX];
|
||||||
ssize_t length = readlink(path_fs, buffer, sizeof(buffer));
|
ssize_t length = readlink(path_fs.c_str(), buffer, sizeof(buffer));
|
||||||
g_free(path_fs);
|
|
||||||
if (length < 0)
|
if (length < 0)
|
||||||
/* don't skip if this is not a symlink */
|
/* don't skip if this is not a symlink */
|
||||||
return errno != EINVAL;
|
return errno != EINVAL;
|
||||||
@ -359,24 +352,19 @@ update_directory(Directory *directory, const struct stat *st)
|
|||||||
|
|
||||||
directory_set_stat(directory, st);
|
directory_set_stat(directory, st);
|
||||||
|
|
||||||
char *path_fs = map_directory_fs(directory);
|
const Path path_fs = map_directory_fs(directory);
|
||||||
if (path_fs == NULL)
|
if (path_fs.IsNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DIR *dir = opendir(path_fs);
|
DIR *dir = opendir(path_fs.c_str());
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
g_warning("Failed to open directory %s: %s",
|
g_warning("Failed to open directory %s: %s",
|
||||||
path_fs, g_strerror(errno));
|
path_fs.c_str(), g_strerror(errno));
|
||||||
g_free(path_fs);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *exclude_path_fs = g_build_filename(path_fs, ".mpdignore", NULL);
|
|
||||||
ExcludeList exclude_list;
|
ExcludeList exclude_list;
|
||||||
exclude_list.LoadFile(exclude_path_fs);
|
exclude_list.LoadFile(Path::Build(path_fs, ".mpdignore"));
|
||||||
g_free(exclude_path_fs);
|
|
||||||
|
|
||||||
g_free(path_fs);
|
|
||||||
|
|
||||||
if (!exclude_list.IsEmpty())
|
if (!exclude_list.IsEmpty())
|
||||||
remove_excluded_from_directory(directory, exclude_list);
|
remove_excluded_from_directory(directory, exclude_list);
|
||||||
|
@ -68,7 +68,7 @@ SimpleDatabase::Configure(const struct config_param *param, GError **error_r)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = _path;
|
path = Path::FromUTF8(_path);
|
||||||
free(_path);
|
free(_path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -77,6 +77,7 @@ SimpleDatabase::Configure(const struct config_param *param, GError **error_r)
|
|||||||
bool
|
bool
|
||||||
SimpleDatabase::Check(GError **error_r) const
|
SimpleDatabase::Check(GError **error_r) const
|
||||||
{
|
{
|
||||||
|
assert(!path.IsNull());
|
||||||
assert(!path.empty());
|
assert(!path.empty());
|
||||||
|
|
||||||
/* Check if the file exists */
|
/* Check if the file exists */
|
||||||
@ -153,7 +154,7 @@ SimpleDatabase::Load(GError **error_r)
|
|||||||
assert(!path.empty());
|
assert(!path.empty());
|
||||||
assert(root != NULL);
|
assert(root != NULL);
|
||||||
|
|
||||||
TextFile file(path.c_str());
|
TextFile file(path);
|
||||||
if (file.HasFailed()) {
|
if (file.HasFailed()) {
|
||||||
g_set_error(error_r, simple_db_quark(), errno,
|
g_set_error(error_r, simple_db_quark(), errno,
|
||||||
"Failed to open database file \"%s\": %s",
|
"Failed to open database file \"%s\": %s",
|
||||||
|
@ -21,17 +21,17 @@
|
|||||||
#define MPD_SIMPLE_DATABASE_PLUGIN_HXX
|
#define MPD_SIMPLE_DATABASE_PLUGIN_HXX
|
||||||
|
|
||||||
#include "DatabasePlugin.hxx"
|
#include "DatabasePlugin.hxx"
|
||||||
|
#include "Path.hxx"
|
||||||
#include "gcc.h"
|
#include "gcc.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
struct Directory;
|
struct Directory;
|
||||||
|
|
||||||
class SimpleDatabase : public Database {
|
class SimpleDatabase : public Database {
|
||||||
std::string path;
|
Path path;
|
||||||
|
|
||||||
Directory *root;
|
Directory *root;
|
||||||
|
|
||||||
@ -41,6 +41,9 @@ class SimpleDatabase : public Database {
|
|||||||
unsigned borrowed_song_count;
|
unsigned borrowed_song_count;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SimpleDatabase()
|
||||||
|
:path(Path::Null()) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
gcc_pure
|
gcc_pure
|
||||||
Directory *GetRoot() {
|
Directory *GetRoot() {
|
||||||
|
Loading…
Reference in New Issue
Block a user