2 * Copyright (C) 2003-2009 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "directory.h"
27 #include "decoder_list.h"
28 #include "archive_list.h"
30 #include "event_pipe.h"
41 #include "song_sticker.h"
47 #include <sys/types.h>
55 #include "decoder_plugin.h"
58 #define G_LOG_DOMAIN "update"
60 static enum update_progress
{
61 UPDATE_PROGRESS_IDLE
= 0,
62 UPDATE_PROGRESS_RUNNING
= 1,
63 UPDATE_PROGRESS_DONE
= 2
68 /* make this dynamic?, or maybe this is big enough... */
69 static char *update_paths
[32];
70 static size_t update_paths_nr
;
72 static GThread
*update_thr
;
74 static const unsigned update_task_id_max
= 1 << 15;
76 static unsigned update_task_id
;
78 static struct song
*delete;
80 /** used by the main thread to notify the update thread */
81 static struct notify update_notify
;
86 DEFAULT_FOLLOW_INSIDE_SYMLINKS
= true,
87 DEFAULT_FOLLOW_OUTSIDE_SYMLINKS
= true,
90 static bool follow_inside_symlinks
;
91 static bool follow_outside_symlinks
;
98 return (progress
!= UPDATE_PROGRESS_IDLE
) ? update_task_id
: 0;
102 directory_set_stat(struct directory
*dir
, const struct stat
*st
)
104 dir
->inode
= st
->st_ino
;
105 dir
->device
= st
->st_dev
;
110 delete_song(struct directory
*dir
, struct song
*del
)
112 /* first, prevent traversers in main task from getting this */
113 songvec_delete(&dir
->songs
, del
);
115 /* now take it out of the playlist (in the main_task) */
118 event_pipe_emit(PIPE_EVENT_DELETE
);
121 notify_wait(&update_notify
);
122 } while (delete != NULL
);
124 /* finally, all possible references gone, free it */
129 delete_each_song(struct song
*song
, G_GNUC_UNUSED
void *data
)
131 struct directory
*directory
= data
;
132 assert(song
->parent
== directory
);
133 delete_song(directory
, song
);
138 delete_directory(struct directory
*directory
);
141 * Recursively remove all sub directories and songs from a directory,
142 * leaving an empty directory.
145 clear_directory(struct directory
*directory
)
149 for (i
= directory
->children
.nr
; --i
>= 0;)
150 delete_directory(directory
->children
.base
[i
]);
152 assert(directory
->children
.nr
== 0);
154 songvec_for_each(&directory
->songs
, delete_each_song
, directory
);
158 * Recursively free a directory and all its contents.
161 delete_directory(struct directory
*directory
)
163 assert(directory
->parent
!= NULL
);
165 clear_directory(directory
);
167 dirvec_delete(&directory
->parent
->children
, directory
);
168 directory_free(directory
);
172 delete_name_in(struct directory
*parent
, const char *name
)
174 struct directory
*directory
= directory_get_child(parent
, name
);
175 struct song
*song
= songvec_find(&parent
->songs
, name
);
177 if (directory
!= NULL
) {
178 delete_directory(directory
);
183 delete_song(parent
, song
);
188 /* passed to songvec_for_each */
190 delete_song_if_removed(struct song
*song
, void *_data
)
192 struct directory
*dir
= _data
;
196 if ((path
= map_song_fs(song
)) == NULL
||
197 stat(path
, &st
) < 0 || !S_ISREG(st
.st_mode
)) {
198 delete_song(dir
, song
);
207 directory_exists(const struct directory
*directory
)
213 path_fs
= map_directory_fs(directory
);
215 /* invalid path: cannot exist */
218 test
= directory
->device
== DEVICE_INARCHIVE
||
219 directory
->device
== DEVICE_CONTAINER
220 ? G_FILE_TEST_IS_REGULAR
221 : G_FILE_TEST_IS_DIR
;
223 exists
= g_file_test(path_fs
, test
);
230 removeDeletedFromDirectory(struct directory
*directory
)
233 struct dirvec
*dv
= &directory
->children
;
235 for (i
= dv
->nr
; --i
>= 0; ) {
236 if (directory_exists(dv
->base
[i
]))
239 g_debug("removing directory: %s", dv
->base
[i
]->path
);
240 delete_directory(dv
->base
[i
]);
244 songvec_for_each(&directory
->songs
, delete_song_if_removed
, directory
);
248 stat_directory(const struct directory
*directory
, struct stat
*st
)
253 path_fs
= map_directory_fs(directory
);
256 ret
= stat(path_fs
, st
);
262 stat_directory_child(const struct directory
*parent
, const char *name
,
268 path_fs
= map_directory_child_fs(parent
, name
);
272 ret
= stat(path_fs
, st
);
278 statDirectory(struct directory
*dir
)
282 if (stat_directory(dir
, &st
) < 0)
285 directory_set_stat(dir
, &st
);
291 inodeFoundInParent(struct directory
*parent
, ino_t inode
, dev_t device
)
294 if (!parent
->stat
&& statDirectory(parent
) < 0)
296 if (parent
->inode
== inode
&& parent
->device
== device
) {
297 g_debug("recursive directory found");
300 parent
= parent
->parent
;
306 static struct directory
*
307 make_subdir(struct directory
*parent
, const char *name
)
309 struct directory
*directory
;
311 directory
= directory_get_child(parent
, name
);
312 if (directory
== NULL
) {
315 if (directory_is_root(parent
))
318 name
= path
= g_strconcat(directory_get_path(parent
),
321 directory
= directory_new_child(parent
, name
);
328 #ifdef ENABLE_ARCHIVE
330 update_archive_tree(struct directory
*directory
, char *name
)
332 struct directory
*subdir
;
336 tmp
= strchr(name
, '/');
339 //add dir is not there already
340 if ((subdir
= dirvec_find(&directory
->children
, name
)) == NULL
) {
341 //create new directory
342 subdir
= make_subdir(directory
, name
);
343 subdir
->device
= DEVICE_INARCHIVE
;
345 //create directories first
346 update_archive_tree(subdir
, tmp
+1);
348 if (strlen(name
) == 0) {
349 g_warning("archive returned directory only");
353 song
= songvec_find(&directory
->songs
, name
);
355 song
= song_file_load(name
, directory
);
357 songvec_add(&directory
->songs
, song
);
359 g_message("added %s/%s",
360 directory_get_path(directory
), name
);
367 * Updates the file listing from an archive file.
369 * @param parent the parent directory the archive file resides in
370 * @param name the UTF-8 encoded base name of the archive file
371 * @param st stat() information on the archive file
372 * @param plugin the archive plugin which fits this archive type
375 update_archive_file(struct directory
*parent
, const char *name
,
376 const struct stat
*st
,
377 const struct archive_plugin
*plugin
)
380 struct archive_file
*file
;
381 struct directory
*directory
;
384 directory
= dirvec_find(&parent
->children
, name
);
385 if (directory
!= NULL
&& directory
->mtime
== st
->st_mtime
)
386 /* MPD has already scanned the archive, and it hasn't
387 changed since - don't consider updating it */
390 path_fs
= map_directory_child_fs(parent
, name
);
393 file
= plugin
->open(path_fs
);
395 g_warning("unable to open archive %s", path_fs
);
400 g_debug("archive %s opened", path_fs
);
403 if (directory
== NULL
) {
404 g_debug("creating archive directory: %s", name
);
405 directory
= make_subdir(parent
, name
);
406 /* mark this directory as archive (we use device for
408 directory
->device
= DEVICE_INARCHIVE
;
411 directory
->mtime
= st
->st_mtime
;
413 plugin
->scan_reset(file
);
415 while ((filepath
= plugin
->scan_next(file
)) != NULL
) {
416 /* split name into directory and file */
417 g_debug("adding archive file: %s", filepath
);
418 update_archive_tree(directory
, filepath
);
426 update_container_file( struct directory
* directory
,
428 const struct stat
* st
,
429 const struct decoder_plugin
* plugin
)
432 unsigned int tnum
= 0;
433 char* pathname
= map_directory_child_fs(directory
, name
);
434 struct directory
* contdir
= dirvec_find(&directory
->children
, name
);
436 // directory exists already
439 // modification time not eq. file mod. time
440 if (contdir
->mtime
!= st
->st_mtime
)
442 g_message("removing container file: %s", pathname
);
444 delete_directory(contdir
);
455 contdir
= make_subdir(directory
, name
);
456 contdir
->mtime
= st
->st_mtime
;
457 contdir
->device
= DEVICE_CONTAINER
;
459 while ((vtrack
= plugin
->container_scan(pathname
, ++tnum
)) != NULL
)
461 struct song
* song
= song_file_new(vtrack
, contdir
);
465 // shouldn't be necessary but it's there..
466 song
->mtime
= st
->st_mtime
;
468 song
->tag
= plugin
->tag_dup(map_directory_child_fs(contdir
, vtrack
));
470 songvec_add(&contdir
->songs
, song
);
482 delete_directory(contdir
);
490 update_regular_file(struct directory
*directory
,
491 const char *name
, const struct stat
*st
)
493 const char *suffix
= uri_get_suffix(name
);
494 const struct decoder_plugin
* plugin
;
495 #ifdef ENABLE_ARCHIVE
496 const struct archive_plugin
*archive
;
501 if ((plugin
= decoder_plugin_from_suffix(suffix
, false)) != NULL
)
503 struct song
* song
= songvec_find(&directory
->songs
, name
);
505 if (plugin
->container_scan
!= NULL
)
507 if (update_container_file(directory
, name
, st
, plugin
))
510 delete_song(directory
, song
);
517 song
= song_file_load(name
, directory
);
521 songvec_add(&directory
->songs
, song
);
523 g_message("added %s/%s",
524 directory_get_path(directory
), name
);
525 } else if (st
->st_mtime
!= song
->mtime
) {
526 g_message("updating %s/%s",
527 directory_get_path(directory
), name
);
528 if (!song_file_update(song
))
529 delete_song(directory
, song
);
532 #ifdef ENABLE_ARCHIVE
533 } else if ((archive
= archive_plugin_from_suffix(suffix
))) {
534 update_archive_file(directory
, name
, st
, archive
);
540 updateDirectory(struct directory
*directory
, const struct stat
*st
);
543 updateInDirectory(struct directory
*directory
,
544 const char *name
, const struct stat
*st
)
546 assert(strchr(name
, '/') == NULL
);
548 if (S_ISREG(st
->st_mode
)) {
549 update_regular_file(directory
, name
, st
);
550 } else if (S_ISDIR(st
->st_mode
)) {
551 struct directory
*subdir
;
554 if (inodeFoundInParent(directory
, st
->st_ino
, st
->st_dev
))
557 subdir
= make_subdir(directory
, name
);
558 assert(directory
== subdir
->parent
);
560 ret
= updateDirectory(subdir
, st
);
562 delete_directory(subdir
);
564 g_debug("update: %s is not a directory, archive or music", name
);
568 /* we don't look at "." / ".." nor files with newlines in their name */
569 static bool skip_path(const char *path
)
571 return (path
[0] == '.' && path
[1] == 0) ||
572 (path
[0] == '.' && path
[1] == '.' && path
[2] == 0) ||
573 strchr(path
, '\n') != NULL
;
577 skip_symlink(const struct directory
*directory
, const char *utf8_name
)
580 char buffer
[MPD_PATH_MAX
];
585 path_fs
= map_directory_child_fs(directory
, utf8_name
);
589 ret
= readlink(path_fs
, buffer
, sizeof(buffer
));
592 /* don't skip if this is not a symlink */
593 return errno
!= EINVAL
;
595 if (!follow_inside_symlinks
&& !follow_outside_symlinks
) {
596 /* ignore all symlinks */
598 } else if (follow_inside_symlinks
&& follow_outside_symlinks
) {
599 /* consider all symlinks */
603 if (buffer
[0] == '/')
604 return !follow_outside_symlinks
;
608 if (p
[1] == '.' && p
[2] == '/') {
609 /* "../" moves to parent directory */
610 directory
= directory
->parent
;
611 if (directory
== NULL
) {
612 /* we have moved outside the music
613 directory - skip this symlink
614 if such symlinks are not allowed */
615 return !follow_outside_symlinks
;
618 } else if (p
[1] == '/')
625 /* we are still in the music directory, so this symlink points
626 to a song which is already in the database - skip according
627 to the follow_inside_symlinks param*/
628 return !follow_inside_symlinks
;
630 /* no symlink checking on WIN32 */
640 updateDirectory(struct directory
*directory
, const struct stat
*st
)
646 assert(S_ISDIR(st
->st_mode
));
648 directory_set_stat(directory
, st
);
650 path_fs
= map_directory_fs(directory
);
654 dir
= opendir(path_fs
);
656 g_warning("Failed to open directory %s: %s",
657 path_fs
, g_strerror(errno
));
664 removeDeletedFromDirectory(directory
);
666 while ((ent
= readdir(dir
))) {
670 if (skip_path(ent
->d_name
))
673 utf8
= fs_charset_to_utf8(ent
->d_name
);
674 if (utf8
== NULL
|| skip_symlink(directory
, utf8
)) {
679 if (stat_directory_child(directory
, utf8
, &st2
) == 0)
680 updateInDirectory(directory
, utf8
, &st2
);
682 delete_name_in(directory
, utf8
);
689 directory
->mtime
= st
->st_mtime
;
694 static struct directory
*
695 directory_make_child_checked(struct directory
*parent
, const char *path
)
697 struct directory
*directory
;
700 struct song
*conflicting
;
702 directory
= directory_get_child(parent
, path
);
703 if (directory
!= NULL
)
706 base
= g_path_get_basename(path
);
708 if (stat_directory_child(parent
, base
, &st
) < 0 ||
709 inodeFoundInParent(parent
, st
.st_ino
, st
.st_dev
)) {
714 /* if we're adding directory paths, make sure to delete filenames
715 with potentially the same name */
716 conflicting
= songvec_find(&parent
->songs
, base
);
718 delete_song(parent
, conflicting
);
722 directory
= directory_new_child(parent
, path
);
723 directory_set_stat(directory
, &st
);
727 static struct directory
*
728 addParentPathToDB(const char *utf8path
)
730 struct directory
*directory
= db_get_root();
731 char *duplicated
= g_strdup(utf8path
);
732 char *slash
= duplicated
;
734 while ((slash
= strchr(slash
, '/')) != NULL
) {
737 directory
= directory_make_child_checked(directory
,
739 if (directory
== NULL
|| slash
== NULL
)
750 updatePath(const char *path
)
752 struct directory
*parent
;
756 parent
= addParentPathToDB(path
);
760 name
= g_path_get_basename(path
);
762 if (stat_directory_child(parent
, name
, &st
) == 0)
763 updateInDirectory(parent
, name
, &st
);
765 delete_name_in(parent
, name
);
770 static void * update_task(void *_path
)
772 if (_path
!= NULL
&& !isRootDirectory(_path
)) {
773 updatePath((char *)_path
);
775 struct directory
*directory
= db_get_root();
778 if (stat_directory(directory
, &st
) == 0)
779 updateDirectory(directory
, &st
);
784 if (modified
|| !db_exists())
787 progress
= UPDATE_PROGRESS_DONE
;
788 event_pipe_emit(PIPE_EVENT_UPDATE
);
792 static void spawn_update_task(char *path
)
796 assert(g_thread_self() == main_task
);
798 progress
= UPDATE_PROGRESS_RUNNING
;
800 if (!(update_thr
= g_thread_create(update_task
, path
, TRUE
, &e
)))
801 g_error("Failed to spawn update task: %s", e
->message
);
802 if (++update_task_id
> update_task_id_max
)
804 g_debug("spawned thread for update job id %i", update_task_id
);
808 directory_update_init(char *path
)
810 assert(g_thread_self() == main_task
);
812 if (!mapper_has_music_directory())
815 if (progress
!= UPDATE_PROGRESS_IDLE
) {
816 unsigned next_task_id
;
818 if (update_paths_nr
== G_N_ELEMENTS(update_paths
)) {
823 assert(update_paths_nr
< G_N_ELEMENTS(update_paths
));
824 update_paths
[update_paths_nr
++] = path
;
825 next_task_id
= update_task_id
+ update_paths_nr
;
827 return next_task_id
> update_task_id_max
? 1 : next_task_id
;
829 spawn_update_task(path
);
831 idle_add(IDLE_UPDATE
);
833 return update_task_id
;
837 * Safely delete a song from the database. This must be done in the
838 * main task, to be sure that there is no pointer left to it.
840 static void song_delete_event(void)
844 assert(progress
== UPDATE_PROGRESS_RUNNING
);
845 assert(delete != NULL
);
847 uri
= song_get_uri(delete);
848 g_debug("removing: %s", uri
);
852 /* if the song has a sticker, delete it */
853 if (sticker_enabled())
854 sticker_song_delete(delete);
857 playlist_delete_song(&g_playlist
, delete);
860 notify_signal(&update_notify
);
864 * Called in the main thread after the database update is finished.
866 static void update_finished_event(void)
868 assert(progress
== UPDATE_PROGRESS_DONE
);
870 g_thread_join(update_thr
);
872 idle_add(IDLE_UPDATE
);
875 /* send "idle" events */
876 playlist_increment_version_all(&g_playlist
);
877 idle_add(IDLE_DATABASE
);
880 if (update_paths_nr
) {
881 /* schedule the next path */
882 char *path
= update_paths
[0];
883 memmove(&update_paths
[0], &update_paths
[1],
884 --update_paths_nr
* sizeof(char *));
885 spawn_update_task(path
);
887 progress
= UPDATE_PROGRESS_IDLE
;
893 void update_global_init(void)
896 follow_inside_symlinks
=
897 config_get_bool(CONF_FOLLOW_INSIDE_SYMLINKS
,
898 DEFAULT_FOLLOW_INSIDE_SYMLINKS
);
900 follow_outside_symlinks
=
901 config_get_bool(CONF_FOLLOW_OUTSIDE_SYMLINKS
,
902 DEFAULT_FOLLOW_OUTSIDE_SYMLINKS
);
905 notify_init(&update_notify
);
907 event_pipe_register(PIPE_EVENT_DELETE
, song_delete_event
);
908 event_pipe_register(PIPE_EVENT_UPDATE
, update_finished_event
);
911 void update_global_finish(void)
913 notify_deinit(&update_notify
);