diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/decoder_thread.c | 21 | ||||
-rw-r--r-- | src/mapper.c | 77 | ||||
-rw-r--r-- | src/mapper.h | 74 | ||||
-rw-r--r-- | src/playlist.c | 1 | ||||
-rw-r--r-- | src/playlist_save.c | 22 | ||||
-rw-r--r-- | src/song.c | 5 | ||||
-rw-r--r-- | src/storedPlaylist.c | 26 | ||||
-rw-r--r-- | src/update.c | 66 |
9 files changed, 241 insertions, 53 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index ca6f8f5ab..2151daa77 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,6 +79,7 @@ mpd_headers = \ os_compat.h \ outputBuffer.h \ path.h \ + mapper.h \ pcm_utils.h \ permission.h \ player_thread.h \ @@ -158,6 +159,7 @@ mpd_SOURCES = \ compress.c \ outputBuffer.c \ path.c \ + mapper.c \ pcm_utils.c \ permission.c \ player_thread.c \ diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 594bfbc77..f0f315f3a 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -22,27 +22,28 @@ #include "decoder_internal.h" #include "player_control.h" #include "song.h" - +#include "mapper.h" #include "path.h" #include "log.h" #include "ls.h" static void decodeStart(void) { + struct song *song = dc.next_song; struct decoder decoder; int ret; bool close_instream = true; InputStream inStream; struct decoder_plugin *plugin = NULL; char path_max_fs[MPD_PATH_MAX]; - char path_max_utf8[MPD_PATH_MAX]; - song_get_url(dc.next_song, path_max_utf8); - if (!isRemoteUrl(path_max_utf8)) { - rmp2amp_r(path_max_fs, - utf8_to_fs_charset(path_max_fs, path_max_utf8)); - } else + if (song_is_file(song)) + map_song_fs(song, path_max_fs); + else { + char path_max_utf8[MPD_PATH_MAX]; + song_get_url(song, path_max_utf8); pathcpy_trunc(path_max_fs, path_max_utf8); + } dc.current_song = dc.next_song; /* NEED LOCK */ if (openInputStream(&inStream, path_max_fs) < 0) { @@ -74,7 +75,7 @@ static void decodeStart(void) goto stop; ret = DECODE_ERROR_UNKTYPE; - if (isRemoteUrl(path_max_utf8)) { + if (!song_is_file(song)) { unsigned int next = 0; /* first we try mime types: */ @@ -92,7 +93,7 @@ static void decodeStart(void) /* if that fails, try suffix matching the URL: */ if (plugin == NULL) { - const char *s = getSuffix(path_max_utf8); + const char *s = getSuffix(path_max_fs); next = 0; while (ret && (plugin = decoder_plugin_from_suffix(s, next++))) { if (plugin->stream_decode == NULL) @@ -123,7 +124,7 @@ static void decodeStart(void) } } else { unsigned int next = 0; - const char *s = getSuffix(path_max_utf8); + const char *s = getSuffix(path_max_fs); while (ret && (plugin = decoder_plugin_from_suffix(s, next++))) { if (!plugin->stream_types & INPUT_PLUGIN_STREAM_FILE) continue; diff --git a/src/mapper.c b/src/mapper.c new file mode 100644 index 000000000..392211214 --- /dev/null +++ b/src/mapper.c @@ -0,0 +1,77 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2008 Max Kellermann <max@duempel.org> + * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Maps directory and song objects to file system paths. + */ + +#include "mapper.h" +#include "directory.h" +#include "song.h" +#include "path.h" + +const char * +map_directory_fs(const struct directory *directory, char *buffer) +{ + const char *dirname = directory_get_path(directory); + if (isRootDirectory(dirname)) + return musicDir; + + return rmp2amp_r(buffer, utf8_to_fs_charset(buffer, dirname)); +} + +const char * +map_directory_child_fs(const struct directory *directory, const char *name, + char *buffer) +{ + char buffer2[MPD_PATH_MAX]; + const char *parent_fs; + + parent_fs = map_directory_fs(directory, buffer2); + if (parent_fs == NULL) + return NULL; + + utf8_to_fs_charset(buffer, name); + pfx_dir(buffer, name, strlen(name), + parent_fs, strlen(parent_fs)); + return buffer; +} + +const char * +map_song_fs(const struct song *song, char *buffer) +{ + assert(song->parent != NULL); + + return map_directory_child_fs(song->parent, song->url, buffer); +} + +const char * +map_fs_to_utf8(const char *path_fs, char *buffer) +{ + size_t music_path_length = strlen(musicDir); + + if (strncmp(path_fs, musicDir, music_path_length) == 0 && + path_fs[music_path_length] == '/') + /* remove musicDir prefix */ + path_fs += music_path_length; + else if (path_fs[0] == '/') + /* not within musicDir */ + return NULL; + + return fs_charset_to_utf8(buffer, path_fs); +} diff --git a/src/mapper.h b/src/mapper.h new file mode 100644 index 000000000..2c21a68e8 --- /dev/null +++ b/src/mapper.h @@ -0,0 +1,74 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2008 Max Kellermann <max@duempel.org> + * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Maps directory and song objects to file system paths. + */ + +#ifndef MAPPER_H +#define MAPPER_H + +struct directory; +struct song; + +/** + * Determines the file system path of a directory object. + * + * @param directory the directory object + * @param a buffer which is MPD_PATH_MAX bytes long + * @return the path in file system encoding, or NULL if mapping failed + */ +const char * +map_directory_fs(const struct directory *directory, char *buffer); + +/** + * Determines the file system path of a directory's child (may be a + * sub directory or a song). + * + * @param directory the parent directory object + * @param name the child's name in UTF-8 + * @param a buffer which is MPD_PATH_MAX bytes long + * @return the path in file system encoding, or NULL if mapping failed + */ +const char * +map_directory_child_fs(const struct directory *directory, const char *name, + char *buffer); + +/** + * Determines the file system path of a song. This must not be a + * remote song. + * + * @param song the song object + * @param a buffer which is MPD_PATH_MAX bytes long + * @return the path in file system encoding, or NULL if mapping failed + */ +const char * +map_song_fs(const struct song *song, char *buffer); + +/** + * Maps a file system path (relative to the music directory or + * absolute) to a relative path in UTF-8 encoding. + * + * @param path_fs a path in file system encoding + * @param buffer a buffer which is MPD_PATH_MAX bytes long + * @return the relative path in UTF-8, or NULL if mapping failed + */ +const char * +map_fs_to_utf8(const char *path_fs, char *buffer); + +#endif diff --git a/src/playlist.c b/src/playlist.c index 65e7d6391..b160202bf 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -28,6 +28,7 @@ #include "conf.h" #include "database.h" #include "log.h" +#include "mapper.h" #include "path.h" #include "utils.h" #include "state_file.h" diff --git a/src/playlist_save.c b/src/playlist_save.c index 98979e2a2..55cd6bd87 100644 --- a/src/playlist_save.c +++ b/src/playlist_save.c @@ -19,21 +19,25 @@ #include "playlist_save.h" #include "playlist.h" #include "song.h" +#include "mapper.h" #include "path.h" #include "ls.h" +#include "database.h" void playlist_print_song(FILE *file, const struct song *song) { char tmp1[MPD_PATH_MAX], tmp2[MPD_PATH_MAX]; - song_get_url(song, tmp1); - utf8_to_fs_charset(tmp2, tmp1); - - if (playlist_saveAbsolutePaths && song_is_file(song)) - fprintf(file, "%s\n", rmp2amp_r(tmp2, tmp2)); - else + if (playlist_saveAbsolutePaths && song_is_file(song)) { + const char *path = map_song_fs(song, tmp1); + if (path != NULL) + fprintf(file, "%s\n", path); + } else { + song_get_url(song, tmp1); + utf8_to_fs_charset(tmp2, tmp1); fprintf(file, "%s\n", tmp2); + } } void @@ -42,8 +46,10 @@ playlist_print_uri(FILE *file, const char *uri) char tmp[MPD_PATH_MAX]; const char *s; - s = utf8_to_fs_charset(tmp, uri); if (playlist_saveAbsolutePaths && !isValidRemoteUtf8Url(s)) - s = rmp2amp_r(tmp, s); + s = map_directory_child_fs(db_get_root(), uri, tmp); + else + s = utf8_to_fs_charset(tmp, uri); + fprintf(file, "%s\n", s); } diff --git a/src/song.c b/src/song.c index 2de9e52c7..b4ab28cab 100644 --- a/src/song.c +++ b/src/song.c @@ -21,6 +21,7 @@ #include "directory.h" #include "utils.h" #include "log.h" +#include "mapper.h" #include "path.h" #include "playlist.h" #include "decoder_list.h" @@ -95,14 +96,12 @@ song_file_update(struct song *song) { struct decoder_plugin *plugin; unsigned int next = 0; - char path_max_tmp[MPD_PATH_MAX]; char abs_path[MPD_PATH_MAX]; struct stat st; assert(song_is_file(song)); - utf8_to_fs_charset(abs_path, song_get_url(song, path_max_tmp)); - rmp2amp_r(abs_path, abs_path); + map_song_fs(song, abs_path); if (song->tag != NULL) { tag_free(song->tag); diff --git a/src/storedPlaylist.c b/src/storedPlaylist.c index 4e20a6de4..3d5b8286f 100644 --- a/src/storedPlaylist.c +++ b/src/storedPlaylist.c @@ -19,6 +19,7 @@ #include "storedPlaylist.h" #include "playlist_save.h" #include "song.h" +#include "mapper.h" #include "path.h" #include "utils.h" #include "ls.h" @@ -91,7 +92,6 @@ List *loadStoredPlaylist(const char *utf8path) FILE *file; char buffer[MPD_PATH_MAX]; char path_max_tmp[MPD_PATH_MAX]; - const size_t musicDir_len = strlen(musicDir); if (!is_valid_playlist_name(utf8path)) return NULL; @@ -105,19 +105,27 @@ List *loadStoredPlaylist(const char *utf8path) while (myFgets(buffer, sizeof(buffer), file)) { char *s = buffer; - struct song *song; + const char *path_utf8; if (*s == PLAYLIST_COMMENT) continue; - if (s[musicDir_len] == '/' && - !strncmp(s, musicDir, musicDir_len)) - memmove(s, s + musicDir_len + 1, - strlen(s + musicDir_len + 1) + 1); - if ((song = db_get_song(s))) { + + if (isValidRemoteUtf8Url(s)) + insertInListWithoutKey(list, xstrdup(s)); + else { + struct song *song; + + path_utf8 = map_fs_to_utf8(s, path_max_tmp); + if (path_utf8 == NULL) + continue; + + song = db_get_song(path_utf8); + if (song == NULL) + continue; + song_get_url(song, path_max_tmp); insertInListWithoutKey(list, xstrdup(path_max_tmp)); - } else if (isValidRemoteUtf8Url(s)) - insertInListWithoutKey(list, xstrdup(s)); + } if (list->numberOfNodes >= playlist_max_length) break; diff --git a/src/update.c b/src/update.c index 93ba1668c..e36a980dd 100644 --- a/src/update.c +++ b/src/update.c @@ -23,6 +23,7 @@ #include "song.h" #include "log.h" #include "ls.h" +#include "mapper.h" #include "path.h" #include "playlist.h" #include "utils.h" @@ -150,11 +151,11 @@ static int delete_song_if_removed(struct song *song, void *_data) { struct delete_data *data = _data; + const char *path; + struct stat st; - data->tmp = song_get_url(song, data->tmp); - assert(data->tmp); - - if (!isFile(data->tmp, NULL)) { + if ((path = map_song_fs(song, data->tmp)) == NULL || + stat(data->tmp, &st) < 0 || !S_ISREG(st.st_mode)) { delete_song(data->dir, song); modified = true; } @@ -169,7 +170,12 @@ removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) struct delete_data data; for (i = dv->nr; --i >= 0; ) { - if (isDir(dv->base[i]->path)) + const char *path_fs; + struct stat st; + + path_fs = map_directory_fs(dv->base[i], path_max_tmp); + if (path_fs == NULL || (stat(path_fs, &st) == 0 && + S_ISDIR(st.st_mode))) continue; LOG("removing directory: %s\n", dv->base[i]->path); dirvec_delete(dv, dv->base[i]); @@ -181,12 +187,26 @@ removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) songvec_for_each(&directory->songs, delete_song_if_removed, &data); } -static const char *opendir_path(char *path_max_tmp, const char *dirname) +static int +stat_directory(const struct directory *directory, struct stat *st) { - if (*dirname != '\0') - return rmp2amp_r(path_max_tmp, - utf8_to_fs_charset(path_max_tmp, dirname)); - return musicDir; + char buffer[MPD_PATH_MAX]; + const char *path_fs; + + path_fs = map_directory_fs(directory, buffer); + if (path_fs == NULL) + return -1; + return stat(path_fs, st); +} + +static int +stat_directory_child(const struct directory *parent, const char *name, + struct stat *st) +{ + char path_fs[MPD_PATH_MAX]; + + map_directory_child_fs(parent, name, path_fs); + return stat(path_fs, st); } static int @@ -194,7 +214,7 @@ statDirectory(struct directory *dir) { struct stat st; - if (myStat(directory_get_path(dir), &st) < 0) + if (stat_directory(dir, &st) < 0) return -1; directory_set_stat(dir, &st); @@ -296,15 +316,19 @@ static bool updateDirectory(struct directory *directory, const struct stat *st) { DIR *dir; - const char *dirname = directory_get_path(directory); struct dirent *ent; char path_max_tmp[MPD_PATH_MAX]; + const char *path_fs; assert(S_ISDIR(st->st_mode)); directory_set_stat(directory, st); - dir = opendir(opendir_path(path_max_tmp, dirname)); + path_fs = map_directory_fs(directory, path_max_tmp); + if (path_fs == NULL) + return false; + + dir = opendir(path_fs); if (!dir) return false; @@ -321,15 +345,11 @@ updateDirectory(struct directory *directory, const struct stat *st) if (!utf8) continue; - if (!isRootDirectory(directory->path)) - utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), - dirname, strlen(dirname)); - - if (myStat(path_max_tmp, &st2) == 0) + if (stat_directory_child(directory, utf8, &st2) == 0) updateInDirectory(directory, - mpd_basename(path_max_tmp), &st2); + path_max_tmp, &st2); else - delete_name_in(directory, mpd_basename(path_max_tmp)); + delete_name_in(directory, path_max_tmp); } closedir(dir); @@ -348,7 +368,7 @@ directory_make_child_checked(struct directory *parent, const char *path) if (directory != NULL) return directory; - if (myStat(path, &st) < 0 || + if (stat_directory_child(parent, mpd_basename(path), &st) < 0 || inodeFoundInParent(parent, st.st_ino, st.st_dev)) return NULL; @@ -398,7 +418,7 @@ updatePath(const char *path) name = mpd_basename(path); - if (myStat(path, &st) == 0) + if (stat_directory_child(parent, name, &st) == 0) updateInDirectory(parent, name, &st); else delete_name_in(parent, name); @@ -413,7 +433,7 @@ static void * update_task(void *_path) struct directory *directory = db_get_root(); struct stat st; - if (myStat(directory_get_path(directory), &st) == 0) + if (stat_directory(directory, &st) == 0) updateDirectory(directory, &st); } |