bool update_container_file(struct directory *directory, const char *name, const struct stat *st, const struct decoder_plugin *plugin) { if (plugin->container_scan == NULL) return false; db_lock(); struct directory *contdir = make_directory_if_modified(directory, name, st); if (contdir == NULL) { /* not modified */ db_unlock(); return true; } contdir->device = DEVICE_CONTAINER; db_unlock(); char *const pathname = map_directory_child_fs(directory, name); char *vtrack; unsigned int tnum = 0; while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL) { struct song *song = song_file_new(vtrack, contdir); // shouldn't be necessary but it's there.. song->mtime = st->st_mtime; char *child_path_fs = map_directory_child_fs(contdir, vtrack); song->tag = tag_new(); decoder_plugin_scan_file(plugin, child_path_fs, &add_tag_handler, song->tag); g_free(child_path_fs); db_lock(); directory_add_song(contdir, song); db_unlock(); modified = true; g_message("added %s/%s", directory_get_path(directory), vtrack); g_free(vtrack); } g_free(pathname); if (tnum == 1) { db_lock(); delete_directory(contdir); db_unlock(); return false; } else return true; }
char * map_song_fs(const struct song *song) { assert(song_is_file(song)); if (song_in_database(song)) return map_directory_child_fs(song->parent, song->uri); else return utf8_to_fs_charset(song->uri); }
/** * Updates the file listing from an archive file. * * @param parent the parent directory the archive file resides in * @param name the UTF-8 encoded base name of the archive file * @param st stat() information on the archive file * @param plugin the archive plugin which fits this archive type */ static void update_archive_file(struct directory *parent, const char *name, const struct stat *st, const struct archive_plugin *plugin) { GError *error = NULL; char *path_fs; struct archive_file *file; struct directory *directory; char *filepath; directory = dirvec_find(&parent->children, name); if (directory != NULL && directory->mtime == st->st_mtime && !walk_discard) /* MPD has already scanned the archive, and it hasn't changed since - don't consider updating it */ return; path_fs = map_directory_child_fs(parent, name); /* open archive */ file = archive_file_open(plugin, path_fs, &error); if (file == NULL) { g_free(path_fs); g_warning("%s", error->message); g_error_free(error); return; } g_debug("archive %s opened", path_fs); g_free(path_fs); if (directory == NULL) { g_debug("creating archive directory: %s", name); directory = make_subdir(parent, name); /* mark this directory as archive (we use device for this) */ directory->device = DEVICE_INARCHIVE; } directory->mtime = st->st_mtime; archive_file_scan_reset(file); while ((filepath = archive_file_scan_next(file)) != NULL) { /* split name into directory and file */ g_debug("adding archive file: %s", filepath); update_archive_tree(directory, filepath); } archive_file_close(file); }
static bool directory_child_is_regular(const struct directory *directory, const char *name_utf8) { char *path_fs = map_directory_child_fs(directory, name_utf8); if (path_fs == NULL) return false; struct stat st; bool is_regular = stat(path_fs, &st) == 0 && S_ISREG(st.st_mode); g_free(path_fs); return is_regular; }
static int stat_directory_child(const struct directory *parent, const char *name, struct stat *st) { char *path_fs; int ret; path_fs = map_directory_child_fs(parent, name); if (path_fs == NULL) return -1; ret = stat(path_fs, st); g_free(path_fs); return ret; }
static int stat_directory_child(const struct directory *parent, const char *name, struct stat *st) { char *path_fs; int ret; path_fs = map_directory_child_fs(parent, name); if (path_fs == NULL) return -1; ret = stat(path_fs, st); if (ret < 0) g_warning("Failed to stat %s: %s", path_fs, g_strerror(errno)); g_free(path_fs); return ret; }
/** * Checks if the given permissions on the mapped file are given. */ static bool directory_child_access(const struct directory *directory, const char *name, int mode) { #ifdef WIN32 /* access() is useless on WIN32 */ (void)directory; (void)name; (void)mode; return true; #else char *path = map_directory_child_fs(directory, name); if (path == NULL) /* something went wrong, but that isn't a permission problem */ return true; bool success = access(path, mode) == 0 || errno != EACCES; g_free(path); return success; #endif }
static bool skip_symlink(const struct directory *directory, const char *utf8_name) { #ifndef WIN32 char buffer[MPD_PATH_MAX]; char *path_fs; const char *p; ssize_t ret; path_fs = map_directory_child_fs(directory, utf8_name); if (path_fs == NULL) return true; ret = readlink(path_fs, buffer, sizeof(buffer)); g_free(path_fs); if (ret < 0) /* don't skip if this is not a symlink */ return errno != EINVAL; if (!follow_inside_symlinks && !follow_outside_symlinks) { /* ignore all symlinks */ return true; } else if (follow_inside_symlinks && follow_outside_symlinks) { /* consider all symlinks */ return false; } if (buffer[0] == '/') return !follow_outside_symlinks; p = buffer; while (*p == '.') { if (p[1] == '.' && G_IS_DIR_SEPARATOR(p[2])) { /* "../" moves to parent directory */ directory = directory->parent; if (directory == NULL) { /* we have moved outside the music directory - skip this symlink if such symlinks are not allowed */ return !follow_outside_symlinks; } p += 3; } else if (G_IS_DIR_SEPARATOR(p[1])) /* eliminate "./" */ p += 2; else break; } /* we are still in the music directory, so this symlink points to a song which is already in the database - skip according to the follow_inside_symlinks param*/ return !follow_inside_symlinks; #else /* no symlink checking on WIN32 */ (void)directory; (void)utf8_name; return false; #endif }
static bool update_container_file( struct directory* directory, const char* name, const struct stat* st, const struct decoder_plugin* plugin) { char* vtrack = NULL; unsigned int tnum = 0; char* pathname = map_directory_child_fs(directory, name); struct directory* contdir = dirvec_find(&directory->children, name); // directory exists already if (contdir != NULL) { // modification time not eq. file mod. time if (contdir->mtime != st->st_mtime || walk_discard) { g_message("removing container file: %s", pathname); delete_directory(contdir); contdir = NULL; modified = true; } else { g_free(pathname); return true; } } contdir = make_subdir(directory, name); contdir->mtime = st->st_mtime; contdir->device = DEVICE_CONTAINER; while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL) { struct song* song = song_file_new(vtrack, contdir); char *child_path_fs; // shouldn't be necessary but it's there.. song->mtime = st->st_mtime; child_path_fs = map_directory_child_fs(contdir, vtrack); song->tag = plugin->tag_dup(child_path_fs); g_free(child_path_fs); songvec_add(&contdir->songs, song); modified = true; g_message("added %s/%s", directory_get_path(directory), vtrack); g_free(vtrack); } g_free(pathname); if (tnum == 1) { delete_directory(contdir); return false; } else return true; }