X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=aft.c;h=0544091bdba4e5054b120e24322504f56e38df4f;hp=63a40d790f602c81d6f28e71e02b6d46d907cd5d;hb=9c9d3e49b2f17e5a83b44b009785b9b6dd5b95aa;hpb=80541d0f045e1ed57332800eff9832e0a5b72ddf diff --git a/aft.c b/aft.c index 63a40d79..0544091b 100644 --- a/aft.c +++ b/aft.c @@ -1,8 +1,4 @@ -/* - * Copyright (C) 2007 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* Copyright (C) 2007 Andre Noll , see file COPYING. */ /** \file aft.c Audio file table functions. */ @@ -26,9 +22,31 @@ #include "sideband.h" #include "command.h" -static struct osl_table *audio_file_table; +/* Data about one audio file. Needed for ls and stat output. */ +struct ls_data { + /* Usual audio format handler information. */ + struct afh_info afhi; + /* Audio file selector information. */ + struct afs_info afsi; + /* The full path of the audio file. */ + char *path; + /* The score value (if -a was given). */ + long score; + /* The hash value of the audio file data. */ + unsigned char *hash; +}; + +/* + * The internal state of the audio file table is described by the following + * variables which are private to aft.c. + */ +static struct osl_table *audio_file_table; /* NULL if table not open */ +static struct osl_row *current_aft_row; /* NULL if no audio file open */ +static unsigned char current_hash[HASH_SIZE]; /* only used on sighup */ + static char *status_items; static char *parser_friendly_status_items; +static struct ls_data status_item_ls_data; /** The different sorting methods of the ls command. */ enum ls_sorting_method { @@ -74,20 +92,6 @@ enum ls_listing_mode { LS_MODE_PARSER, }; -/* Data about one audio file. Needed for ls and stat output. */ -struct ls_data { - /* Usual audio format handler information. */ - struct afh_info afhi; - /* Audio file selector information. */ - struct afs_info afsi; - /* The full path of the audio file. */ - char *path; - /* The score value (if -a was given). */ - long score; - /* The hash value of the audio file data. */ - unsigned char *hash; -}; - /** * The size of the individual output fields of the ls command. * @@ -542,10 +546,12 @@ int get_audio_file_path_of_row(const struct osl_row *row, char **path) struct osl_object path_obj; int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_PATH, &path_obj)); + if (ret < 0) - return ret; - *path = path_obj.data; - return 1; + *path = NULL; + else + *path = path_obj.data; + return ret; } /** @@ -754,11 +760,11 @@ static int write_attribute_items(struct para_buffer *b, char *att_text; int ret; - WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_BITMAP, "%s\n", att_bitmap); + WRITE_STATUS_ITEM(b, SI_attributes_bitmap, "%s\n", att_bitmap); ret = get_attribute_text(&afsi->attributes, " ", &att_text); if (ret < 0) return ret; - WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_TXT, "%s\n", att_text); + WRITE_STATUS_ITEM(b, SI_attributes_txt, "%s\n", att_text); free(att_text); return ret; } @@ -767,9 +773,9 @@ static void write_lyrics_items(struct para_buffer *b, struct afs_info *afsi) { char *lyrics_name; - WRITE_STATUS_ITEM(b, SI_LYRICS_ID, "%u\n", afsi->lyrics_id); + WRITE_STATUS_ITEM(b, SI_lyrics_id, "%u\n", afsi->lyrics_id); lyr_get_name_by_id(afsi->lyrics_id, &lyrics_name); - WRITE_STATUS_ITEM(b, SI_LYRICS_NAME, "%s\n", lyrics_name? + WRITE_STATUS_ITEM(b, SI_lyrics_name, "%s\n", lyrics_name? lyrics_name : "(none)"); } @@ -777,9 +783,9 @@ static void write_image_items(struct para_buffer *b, struct afs_info *afsi) { char *image_name; - WRITE_STATUS_ITEM(b, SI_IMAGE_ID, "%u\n", afsi->image_id); + WRITE_STATUS_ITEM(b, SI_image_id, "%u\n", afsi->image_id); img_get_name_by_id(afsi->image_id, &image_name); - WRITE_STATUS_ITEM(b, SI_IMAGE_NAME, "%s\n", image_name? + WRITE_STATUS_ITEM(b, SI_image_name, "%s\n", image_name? image_name : "(none)"); } @@ -789,14 +795,14 @@ static void write_filename_items(struct para_buffer *b, const char *path, char *val; if (basename) { - WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", path); + WRITE_STATUS_ITEM(b, SI_basename, "%s\n", path); return; } - WRITE_STATUS_ITEM(b, SI_PATH, "%s\n", path); + WRITE_STATUS_ITEM(b, SI_path, "%s\n", path); val = para_basename(path); - WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", val? val : ""); + WRITE_STATUS_ITEM(b, SI_basename, "%s\n", val? val : ""); val = para_dirname(path); - WRITE_STATUS_ITEM(b, SI_DIRECTORY, "%s\n", val? val : ""); + WRITE_STATUS_ITEM(b, SI_directory, "%s\n", val? val : ""); free(val); } @@ -913,36 +919,36 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, } write_filename_items(b, d->path, lls_opt_given(r_b)); if (lls_opt_given(r_a)) - WRITE_STATUS_ITEM(b, SI_SCORE, "%li\n", d->score); + WRITE_STATUS_ITEM(b, SI_score, "%li\n", d->score); ret = write_attribute_items(b, att_buf, afsi); if (ret < 0) goto out; write_image_items(b, afsi); write_lyrics_items(b, afsi); hash_to_asc(d->hash, asc_hash); - WRITE_STATUS_ITEM(b, SI_HASH, "%s\n", asc_hash); - WRITE_STATUS_ITEM(b, SI_BITRATE, "%dkbit/s\n", afhi->bitrate); - WRITE_STATUS_ITEM(b, SI_FORMAT, "%s\n", + WRITE_STATUS_ITEM(b, SI_hash, "%s\n", asc_hash); + WRITE_STATUS_ITEM(b, SI_bitrate, "%dkbit/s\n", afhi->bitrate); + WRITE_STATUS_ITEM(b, SI_format, "%s\n", audio_format_name(afsi->audio_format_id)); - WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency); - WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels); - WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf); - WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n", + WRITE_STATUS_ITEM(b, SI_frequency, "%dHz\n", afhi->frequency); + WRITE_STATUS_ITEM(b, SI_channels, "%d\n", afhi->channels); + WRITE_STATUS_ITEM(b, SI_duration, "%s\n", duration_buf); + WRITE_STATUS_ITEM(b, SI_seconds_total, "%" PRIu32 "\n", afhi->seconds_total); - WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time); - WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%u\n", afsi->num_played); - WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp); - WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv)); - WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n", + WRITE_STATUS_ITEM(b, SI_last_played, "%s\n", last_played_time); + WRITE_STATUS_ITEM(b, SI_num_played, "%u\n", afsi->num_played); + WRITE_STATUS_ITEM(b, SI_amplification, "%u\n", afsi->amp); + WRITE_STATUS_ITEM(b, SI_chunk_time, "%lu\n", tv2ms(&afhi->chunk_tv)); + WRITE_STATUS_ITEM(b, SI_num_chunks, "%" PRIu32 "\n", afhi->chunks_total); - WRITE_STATUS_ITEM(b, SI_MAX_CHUNK_SIZE, "%" PRIu32 "\n", + WRITE_STATUS_ITEM(b, SI_max_chunk_size, "%" PRIu32 "\n", afhi->max_chunk_size); - WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo); - WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist); - WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title); - WRITE_STATUS_ITEM(b, SI_YEAR, "%s\n", afhi->tags.year); - WRITE_STATUS_ITEM(b, SI_ALBUM, "%s\n", afhi->tags.album); - WRITE_STATUS_ITEM(b, SI_COMMENT, "%s\n", afhi->tags.comment); + WRITE_STATUS_ITEM(b, SI_techinfo, "%s\n", afhi->techinfo); + WRITE_STATUS_ITEM(b, SI_artist, "%s\n", afhi->tags.artist); + WRITE_STATUS_ITEM(b, SI_title, "%s\n", afhi->tags.title); + WRITE_STATUS_ITEM(b, SI_year, "%s\n", afhi->tags.year); + WRITE_STATUS_ITEM(b, SI_album, "%s\n", afhi->tags.album); + WRITE_STATUS_ITEM(b, SI_comment, "%s\n", afhi->tags.comment); if (opts->mode == LS_MODE_MBOX) { struct osl_object lyrics_def; lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def); @@ -956,9 +962,6 @@ out: return ret; } -static struct ls_data status_item_ls_data; -static struct osl_row *current_aft_row; - static void make_inode_status_items(struct para_buffer *pb) { struct stat statbuf = {.st_size = 0}; @@ -976,8 +979,19 @@ static void make_inode_status_items(struct para_buffer *pb) ret = strftime(mtime_str, 29, "%b %d %Y", &mtime_tm); assert(ret > 0); /* number of bytes placed in mtime_str */ out: - WRITE_STATUS_ITEM(pb, SI_MTIME, "%s\n", mtime_str); - WRITE_STATUS_ITEM(pb, SI_FILE_SIZE, "%ld\n", statbuf.st_size / 1024); + WRITE_STATUS_ITEM(pb, SI_mtime, "%s\n", mtime_str); + WRITE_STATUS_ITEM(pb, SI_file_size, "%ld\n", statbuf.st_size / 1024); +} + +/** + * Deallocate and invalidate the status item strings. + * + * This needs to be a public function so that afs.c can call it on shutdown. + */ +void free_status_items(void) +{ + freep(&status_items); + freep(&parser_friendly_status_items); } static int make_status_items(void) @@ -989,6 +1003,9 @@ static int make_status_items(void) time_t current_time; int ret; + free_status_items(); + if (!status_item_ls_data.path) /* no audio file open */ + return 0; ret = lls_parse(ARRAY_SIZE(argv), argv, cmd, &opts.lpr, NULL); assert(ret >= 0); time(¤t_time); @@ -996,23 +1013,20 @@ static int make_status_items(void) if (ret < 0) goto out; make_inode_status_items(&pb); - free(status_items); status_items = pb.buf; memset(&pb, 0, sizeof(pb)); pb.max_size = shm_get_shmmax() - 1; pb.flags = PBF_SIZE_PREFIX; ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time); - if (ret < 0) { - free(status_items); - status_items = NULL; - return ret; - } + if (ret < 0) + goto out; make_inode_status_items(&pb); - free(parser_friendly_status_items); parser_friendly_status_items = pb.buf; ret = 1; out: + if (ret < 0) + free_status_items(); lls_free_parse_result(opts.lpr, cmd); return ret; } @@ -1590,7 +1604,7 @@ ACTION: Table modifications to be done by the callback. +----+----+---+------+---------------------------------------------------+ | N | N | Y | Y | (new file) create new entry (force has no effect) +----+----+---+------+---------------------------------------------------+ -| N | N | N | Y | (new file) create new entry +| N | N | N | Y | (new file) create new entry +----+----+---+------+---------------------------------------------------+ Notes: @@ -2471,28 +2485,30 @@ int aft_check_attributes(uint64_t att_mask, struct para_buffer *pb) return audio_file_loop(&acad, check_atts_of_audio_file); } -/** - * Close the audio file table. - * - * \param flags Usual flags that are passed to osl_close_table(). - * - * \sa \ref osl_close_table(). +/* + * This sets audio_file_table to NULL, but leaves current_aft_row unmodified, + * though stale (pointing to unmapped memory). If the table is being closed + * because we received SIGHUP, the table will be reopened after the config file + * has been reloaded. We remember the hash of the current audio file here so + * that aft_open() can initialize current_aft_row by looking up the saved hash. */ static void aft_close(void) { + int ret; + unsigned char *p; + + if (current_aft_row) { + ret = get_hash_of_row(current_aft_row, &p); + if (ret < 0) { + PARA_WARNING_LOG("hash lookup failure\n"); + current_aft_row = NULL; + } else + memcpy(current_hash, p, HASH_SIZE); + } osl_close_table(audio_file_table, OSL_MARK_CLEAN); audio_file_table = NULL; } -/** - * Open the audio file table. - * - * \param dir The database directory. - * - * \return Standard. - * - * \sa \ref osl_open_table(). - */ static int aft_open(const char *dir) { int ret; @@ -2503,7 +2519,20 @@ static int aft_open(const char *dir) unsigned num; osl_get_num_rows(audio_file_table, &num); PARA_INFO_LOG("audio file table contains %u files\n", num); - return ret; + if (!current_aft_row) { + PARA_DEBUG_LOG("no current aft row\n"); + return 1; + } + /* SIGHUP case, update current_aft_row */ + ret = aft_get_row_of_hash(current_hash, ¤t_aft_row); + if (ret < 0) { /* not fatal */ + PARA_WARNING_LOG("current hash lookup failure: %s\n", + para_strerror(-ret)); + current_aft_row = NULL; + return 1; + } + PARA_NOTICE_LOG("current audio file hash lookup: success\n"); + return 1; } PARA_NOTICE_LOG("failed to open audio file table\n"); audio_file_table = NULL; @@ -2559,6 +2588,16 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb, status_item_ls_data.afsi.last_played = old_last_played; make_status_items(); return 1; + } case AUDIO_FILE_RENAME: { + char *path; + if (data != current_aft_row) + return 0; + ret = get_audio_file_path_of_row(current_aft_row, &path); + if (ret < 0) + return ret; + status_item_ls_data.path = path; + make_status_items(); + return 1; } case AFHI_CHANGE: { if (data != current_aft_row) return 0; @@ -2567,6 +2606,21 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb, return ret; make_status_items(); return 1; + } case AUDIO_FILE_REMOVE: { + if (data == current_aft_row) + current_aft_row = NULL; + return 0; + } + case BLOB_RENAME: + case BLOB_REMOVE: + case BLOB_ADD: { + /* + * These events are rare. We don't bother to check whether the + * current status items are affected and simply recreate them + * every time. + */ + make_status_items(); + return 0; } default: return 0; }