void directory_save(FILE *fp, struct directory *directory) { struct dirvec *children = &directory->children; size_t i; if (!directory_is_root(directory)) { fprintf(fp, DIRECTORY_MTIME "%lu\n", (unsigned long)directory->mtime); fprintf(fp, "%s%s\n", DIRECTORY_BEGIN, directory_get_path(directory)); } for (i = 0; i < children->nr; ++i) { struct directory *cur = children->base[i]; char *base = g_path_get_basename(cur->path); fprintf(fp, DIRECTORY_DIR "%s\n", base); g_free(base); directory_save(fp, cur); if (ferror(fp)) return; } songvec_save(fp, &directory->songs); if (!directory_is_root(directory)) fprintf(fp, DIRECTORY_END "%s\n", directory_get_path(directory)); }
static void update_regular_file(struct directory *directory, const char *name, const struct stat *st) { const char *suffix = uri_get_suffix(name); const struct decoder_plugin* plugin; #ifdef ENABLE_ARCHIVE const struct archive_plugin *archive; #endif if (suffix == NULL) return; if ((plugin = decoder_plugin_from_suffix(suffix, false)) != NULL) { struct song* song = songvec_find(&directory->songs, name); if (!(song != NULL && st->st_mtime == song->mtime && !walk_discard) && plugin->container_scan != NULL) { if (update_container_file(directory, name, st, plugin)) { if (song != NULL) delete_song(directory, song); return; } } if (song == NULL) { song = song_file_load(name, directory); if (song == NULL) { g_debug("ignoring unrecognized file %s/%s", directory_get_path(directory), name); return; } songvec_add(&directory->songs, song); modified = true; g_message("added %s/%s", directory_get_path(directory), name); } else if (st->st_mtime != song->mtime || walk_discard) { g_message("updating %s/%s", directory_get_path(directory), name); if (!song_file_update(song)) { g_debug("deleting unrecognized file %s/%s", directory_get_path(directory), name); delete_song(directory, song); } modified = true; } #ifdef ENABLE_ARCHIVE } else if ((archive = archive_plugin_from_suffix(suffix))) { update_archive_file(directory, name, st, archive); #endif } }
struct directory * directory_new_child(struct directory *parent, const char *name_utf8) { assert(holding_db_lock()); assert(parent != NULL); assert(name_utf8 != NULL); assert(*name_utf8 != 0); char *allocated; const char *path_utf8; if (directory_is_root(parent)) { allocated = NULL; path_utf8 = name_utf8; } else { allocated = g_strconcat(directory_get_path(parent), "/", name_utf8, NULL); path_utf8 = allocated; } struct directory *directory = directory_new(path_utf8, parent); g_free(allocated); list_add_tail(&directory->siblings, &parent->children); return directory; }
bool sticker_song_find(struct directory *directory, const char *name, void (*func)(struct song *song, const char *value, gpointer user_data), gpointer user_data) { struct sticker_song_find_data data = { .directory = directory, .func = func, .user_data = user_data, }; char *allocated; bool success; data.base_uri = directory_get_path(directory); if (*data.base_uri != 0) /* append slash to base_uri */ data.base_uri = allocated = g_strconcat(data.base_uri, "/", NULL); else /* searching in root directory - no trailing slash */ allocated = NULL; data.base_uri_length = strlen(data.base_uri); success = sticker_find("song", data.base_uri, name, sticker_song_find_cb, &data); g_free(allocated); return success; }
static struct directory * directory_load_subdir(FILE *fp, struct directory *parent, const char *name, GString *buffer, GError **error_r) { struct directory *directory; const char *line; bool success; if (directory_get_child(parent, name) != NULL) { g_set_error(error_r, directory_quark(), 0, "Duplicate subdirectory '%s'", name); return NULL; } if (directory_is_root(parent)) { directory = directory_new(name, parent); } else { char *path = g_strconcat(directory_get_path(parent), "/", name, NULL); directory = directory_new(path, parent); g_free(path); } line = read_text_line(fp, buffer); if (line == NULL) { g_set_error(error_r, directory_quark(), 0, "Unexpected end of file"); directory_free(directory); return NULL; } if (g_str_has_prefix(line, DIRECTORY_MTIME)) { directory->mtime = g_ascii_strtoull(line + sizeof(DIRECTORY_MTIME) - 1, NULL, 10); line = read_text_line(fp, buffer); if (line == NULL) { g_set_error(error_r, directory_quark(), 0, "Unexpected end of file"); directory_free(directory); return NULL; } } if (!g_str_has_prefix(line, DIRECTORY_BEGIN)) { g_set_error(error_r, directory_quark(), 0, "Malformed line: %s", line); directory_free(directory); return NULL; } success = directory_load(fp, directory, buffer, error_r); if (!success) { directory_free(directory); return NULL; } return directory; }
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; }
static int printDirectoryInDirectory(struct directory *directory, void *data) { struct client *client = data; if (!directory_is_root(directory)) client_printf(client, "directory: %s\n", directory_get_path(directory)); return 0; }
char * map_directory_fs(const struct directory *directory) { assert(music_dir != NULL); if (directory_is_root(directory)) return g_strdup(music_dir); return map_uri_fs(directory_get_path(directory)); }
static void print_playlist_in_directory(struct client *client, const struct directory *directory, const char *name_utf8) { if (directory_is_root(directory)) client_printf(client, "playlist: %s\n", name_utf8); else client_printf(client, "playlist: %s/%s\n", directory_get_path(directory), name_utf8); }
static int dirvec_print(struct client *client, const struct dirvec *dv) { size_t i; for (i = 0; i < dv->nr; ++i) client_printf(client, DIRECTORY_DIR "%s\n", directory_get_path(dv->base[i])); return 0; }
static bool print_visitor_directory(const struct directory *directory, void *data, G_GNUC_UNUSED GError **error_r) { struct client *client = data; if (!directory_is_root(directory)) client_printf(client, "directory: %s\n", directory_get_path(directory)); return true; }
char * song_get_uri(const struct song *song) { assert(song != NULL); assert(*song->uri); if (!song_in_database(song) || directory_is_root(song->parent)) return g_strdup(song->uri); else return g_strconcat(directory_get_path(song->parent), "/", song->uri, NULL); }
void song_print_url(struct client *client, struct song *song) { if (song_in_database(song) && !directory_is_root(song->parent)) { client_printf(client, "%s%s/%s\n", SONG_FILE, directory_get_path(song->parent), song->url); } else { char *allocated; const char *uri; uri = allocated = uri_remove_auth(song->url); if (uri == NULL) uri = song->url; client_printf(client, "%s%s\n", SONG_FILE, uri); g_free(allocated); } }
static struct directory * make_subdir(struct directory *parent, const char *name) { struct directory *directory; directory = directory_get_child(parent, name); if (directory == NULL) { char *path; if (directory_is_root(parent)) path = NULL; else name = path = g_strconcat(directory_get_path(parent), "/", name, NULL); directory = directory_new_child(parent, name); g_free(path); } return directory; }
static void update_archive_tree(struct directory *directory, char *name) { struct directory *subdir; struct song *song; char *tmp; tmp = strchr(name, '/'); if (tmp) { *tmp = 0; //add dir is not there already if ((subdir = dirvec_find(&directory->children, name)) == NULL) { //create new directory subdir = make_subdir(directory, name); subdir->device = DEVICE_INARCHIVE; } //create directories first update_archive_tree(subdir, tmp+1); } else { if (strlen(name) == 0) { g_warning("archive returned directory only"); return; } //add file song = songvec_find(&directory->songs, name); if (song == NULL) { song = song_file_load(name, directory); if (song != NULL) { songvec_add(&directory->songs, song); modified = true; g_message("added %s/%s", directory_get_path(directory), name); } } } }
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; }
static void update_song_file2(struct directory *directory, const char *name, const struct stat *st, const struct decoder_plugin *plugin) { db_lock(); struct song *song = directory_get_song(directory, name); db_unlock(); if (!directory_child_access(directory, name, R_OK)) { g_warning("no read permissions on %s/%s", directory_get_path(directory), name); if (song != NULL) { db_lock(); delete_song(directory, song); db_unlock(); } return; } if (!(song != NULL && st->st_mtime == song->mtime && !walk_discard) && update_container_file(directory, name, st, plugin)) { if (song != NULL) { db_lock(); delete_song(directory, song); db_unlock(); } return; } if (song == NULL) { g_debug("reading %s/%s", directory_get_path(directory), name); song = song_file_load(name, directory); if (song == NULL) { g_debug("ignoring unrecognized file %s/%s", directory_get_path(directory), name); return; } db_lock(); directory_add_song(directory, song); db_unlock(); modified = true; g_message("added %s/%s", directory_get_path(directory), name); } else if (st->st_mtime != song->mtime || walk_discard) { g_message("updating %s/%s", directory_get_path(directory), name); if (!song_file_update(song)) { g_debug("deleting unrecognized file %s/%s", directory_get_path(directory), name); db_lock(); delete_song(directory, song); db_unlock(); } modified = true; } }