X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=aft.c;h=35a53904a33a85ba484830bc43cf46ec1ae1bd98;hp=0db2c5803dfa4c100b092f9c022759f1b85e043b;hb=2bad70d84e763b4d866d7b97dbc1cdc8e030bd45;hpb=6bded356ec89b1344049ff702e6c6babaeccd439 diff --git a/aft.c b/aft.c index 0db2c580..35a53904 100644 --- a/aft.c +++ b/aft.c @@ -42,7 +42,7 @@ struct ls_data { */ 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 unsigned char current_hash[HASH2_SIZE]; /* only used on sighup */ static char *status_items; static char *parser_friendly_status_items; @@ -226,7 +226,7 @@ static struct osl_column_description aft_cols[] = { .storage_flags = OSL_RBTREE | OSL_FIXED_SIZE | OSL_UNIQUE, .name = "hash", .compare_function = aft_hash_compare, - .data_size = HASH_SIZE + .data_size = HASH2_SIZE }, [AFTCOL_PATH] = { .storage_type = OSL_MAPPED_STORAGE, @@ -251,7 +251,7 @@ static struct osl_column_description aft_cols[] = { }; static struct osl_table_description audio_file_table_desc = { - .name = "audio_files", + .name = "audio-files", .num_columns = NUM_AFT_COLUMNS, .flags = OSL_LARGE_TABLE, .column_descriptions = aft_cols @@ -396,7 +396,7 @@ static void save_chunk_table(struct afh_info *afhi, char *buf) { uint32_t n; - if (!afhi->chunk_table) + if (!afhi->chunk_table || afhi->chunks_total == 0) return; for (n = 0; n <= afhi->chunks_total; n++) write_u32(buf + 4 * n, afhi->chunk_table[n]); @@ -407,7 +407,7 @@ static void load_chunk_table(struct afh_info *afhi, const struct osl_object *ct) int i; size_t sz; - if (!ct->data || ct->size < 4) { + if (!ct->data || ct->size < 4 * (afhi->chunks_total + 1)) { afhi->chunk_table = NULL; return; } @@ -442,7 +442,7 @@ int aft_get_row_of_path(const char *path, struct osl_row **row) */ static int aft_get_row_of_hash(unsigned char *hash, struct osl_row **row) { - const struct osl_object obj = {.data = hash, .size = HASH_SIZE}; + const struct osl_object obj = {.data = hash, .size = HASH2_SIZE}; return osl(osl_get_row(audio_file_table, AFTCOL_HASH, &obj, row)); } @@ -589,8 +589,10 @@ static int get_hash_of_row(const struct osl_row *row, unsigned char **hash) int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi) { struct osl_object obj; - int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_AFHI, - &obj)); + int ret; + + assert(row); + ret = osl(osl_get_object(audio_file_table, row, AFTCOL_AFHI, &obj)); if (ret < 0) return ret; load_afhi(obj.data, afhi); @@ -719,7 +721,8 @@ __a_const static short unsigned get_duration_width(int seconds) return width + 6; } -static void get_duration_buf(int seconds, char *buf, struct ls_options *opts) +static void get_duration_buf(int seconds, char *buf, size_t bufsize, + struct ls_options *opts) { unsigned hours = seconds / 3600, mins = (seconds % 3600) / 60; short unsigned max_width; @@ -727,10 +730,12 @@ static void get_duration_buf(int seconds, char *buf, struct ls_options *opts) if (!hours) { /* m:ss or mm:ss */ max_width = opts->mode == LS_MODE_LONG? opts->widths.duration_width : 4; + assert(max_width < bufsize - 1); sprintf(buf, "%*u:%02d", max_width - 3, mins, seconds % 60); } else { /* more than one hour => h:mm:ss, hh:mm:ss, hhh:mm:ss, ... */ max_width = opts->mode == LS_MODE_LONG? opts->widths.duration_width : 7; + assert(max_width < bufsize - 1); sprintf(buf, "%*u:%02u:%02d", max_width - 6, hours, mins, seconds % 60); } @@ -833,7 +838,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, char duration_buf[30]; /* nobody has an audio file long enough to overflow this */ struct afs_info *afsi = &d->afsi; struct afh_info *afhi = &d->afhi; - char asc_hash[2 * HASH_SIZE + 1]; + char asc_hash[2 * HASH2_SIZE + 1]; if (opts->mode == LS_MODE_SHORT) { para_printf(b, "%s\n", d->path); @@ -854,7 +859,8 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, if (ret < 0) goto out; } - get_duration_buf(afhi->seconds_total, duration_buf, opts); + get_duration_buf(afhi->seconds_total, duration_buf, + sizeof(duration_buf), opts); if (opts->mode == LS_MODE_LONG) { struct ls_widths *w = &opts->widths; if (lls_opt_given(r_a)) @@ -1018,7 +1024,14 @@ out: /** * Open the audio file with highest score and set up an afd structure. * - * \param afd Result pointer. + * This determines and opens the next audio file, verifies that it did not + * change by comparing the recomputed the hash value of the file contents + * against the value stored in the audio file table. If all goes well, it + * creates a shared memory area containing the serialized version of the afd + * structure, including the chunk table, if any. The caller can then send the + * ID of this area and the open fd to the server process. + * + * \param fd Result pointer for the file descriptor of the audio file. * * On success, the numplayed field of the audio file selector info is increased * and the lastplayed time is set to the current time. Finally, the score of @@ -1026,37 +1039,54 @@ out: * * \return Positive shmid on success, negative on errors. */ -int open_and_update_audio_file(struct audio_file_data *afd) +int open_and_update_audio_file(int *fd) { - unsigned char file_hash[HASH_SIZE]; + unsigned char file_hash[HASH2_SIZE]; struct osl_object afsi_obj; struct afs_info new_afsi; int ret; struct afsi_change_event_data aced; struct osl_object map, chunk_table_obj; struct ls_data *d = &status_item_ls_data; + unsigned char *tmp_hash; + struct audio_file_data afd; again: ret = score_get_best(¤t_aft_row, &d->score); if (ret < 0) return ret; - ret = get_hash_of_row(current_aft_row, &d->hash); + /* + * get_hash_of_row() and get_audio_file_path_of_row() initialize + * their pointer argument to point to memory-mapped files. These pointers + * become stale after a new audio file has been added or after the + * server process received SIGHUP. For in both cases libosl unmaps and + * remaps the underlying database files, and this remapping may well + * change the starting address of the mapping. To avoid stale pointer + * references we create copies on the heap. + */ + ret = get_hash_of_row(current_aft_row, &tmp_hash); if (ret < 0) return ret; + if (!d->hash) + d->hash = para_malloc(HASH_SIZE); + memcpy(d->hash, tmp_hash, HASH_SIZE); + free(d->path); ret = get_audio_file_path_of_row(current_aft_row, &d->path); if (ret < 0) return ret; PARA_NOTICE_LOG("%s\n", d->path); + d->path = para_strdup(d->path); + ret = get_afsi_object_of_row(current_aft_row, &afsi_obj); if (ret < 0) return ret; ret = load_afsi(&d->afsi, &afsi_obj); if (ret < 0) return ret; - ret = get_afhi_of_row(current_aft_row, &afd->afhi); + ret = get_afhi_of_row(current_aft_row, &afd.afhi); if (ret < 0) return ret; - d->afhi = afd->afhi; - d->afhi.chunk_table = afd->afhi.chunk_table = NULL; + d->afhi = afd.afhi; + d->afhi.chunk_table = afd.afhi.chunk_table = NULL; ret = osl(osl_open_disk_object(audio_file_table, current_aft_row, AFTCOL_CHUNKS, &chunk_table_obj)); if (ret < 0) { @@ -1068,10 +1098,10 @@ again: } else { PARA_INFO_LOG("chunk table: %zu bytes\n", chunk_table_obj.size); } - ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, &afd->fd); + ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, fd); if (ret < 0) goto out; - hash_function(map.data, map.size, file_hash); + hash2_function(map.data, map.size, file_hash); ret = hash_compare(file_hash, d->hash); para_munmap(map.data, map.size); if (ret) { @@ -1083,8 +1113,8 @@ again: new_afsi.last_played = time(NULL); save_afsi(&new_afsi, &afsi_obj); /* in-place update */ - afd->audio_format_id = d->afsi.audio_format_id; - load_chunk_table(&afd->afhi, &chunk_table_obj); + afd.audio_format_id = d->afsi.audio_format_id; + load_chunk_table(&afd.afhi, &chunk_table_obj); aced.aft_row = current_aft_row; aced.old_afsi = &d->afsi; /* @@ -1094,9 +1124,9 @@ again: ret = afs_event(AFSI_CHANGE, NULL, &aced); if (ret < 0) goto out; - ret = save_afd(afd); + ret = save_afd(&afd); out: - free(afd->afhi.chunk_table); + free(afd.afhi.chunk_table); if (chunk_table_obj.data) osl_close_disk_object(&chunk_table_obj); if (ret < 0) { @@ -1111,7 +1141,7 @@ out: static int ls_hash_compare(const void *a, const void *b) { struct ls_data *d1 = *(struct ls_data **)a, *d2 = *(struct ls_data **)b; - return memcmp(d1->hash, d2->hash, HASH_SIZE); + return memcmp(d1->hash, d2->hash, HASH2_SIZE); } static int ls_audio_format_compare(const void *a, const void *b) @@ -1506,7 +1536,7 @@ enum com_add_buffer_offsets { /** The hash of the audio file being added. */ CAB_HASH_OFFSET = 13, /** Start of the path of the audio file. */ - CAB_PATH_OFFSET = (CAB_HASH_OFFSET + HASH_SIZE), + CAB_PATH_OFFSET = (CAB_HASH_OFFSET + HASH2_SIZE), }; /* @@ -1529,7 +1559,7 @@ static void save_add_callback_buffer(unsigned char *hash, const char *path, assert(size <= ~(uint32_t)0); write_u8(buf + CAB_AUDIO_FORMAT_ID_OFFSET, audio_format_num); - memcpy(buf + CAB_HASH_OFFSET, hash, HASH_SIZE); + memcpy(buf + CAB_HASH_OFFSET, hash, HASH2_SIZE); strcpy(buf + CAB_PATH_OFFSET, path); pos = CAB_PATH_OFFSET + path_len; write_u32(buf + CAB_AFHI_OFFSET_POS, pos); @@ -1605,7 +1635,7 @@ static int com_add_callback(struct afs_callback_arg *aca) struct osl_row *hs; struct osl_object objs[NUM_AFT_COLUMNS]; unsigned char *hash; - char asc[2 * HASH_SIZE + 1]; + char asc[2 * HASH2_SIZE + 1]; int ret; char afsi_buf[AFSI_SIZE]; char *slpr = buf + read_u32(buf + CAB_LPR_OFFSET); @@ -1622,7 +1652,7 @@ static int com_add_callback(struct afs_callback_arg *aca) hash = (unsigned char *)buf + CAB_HASH_OFFSET; hash_to_asc(hash, asc); objs[AFTCOL_HASH].data = buf + CAB_HASH_OFFSET; - objs[AFTCOL_HASH].size = HASH_SIZE; + objs[AFTCOL_HASH].size = HASH2_SIZE; path = buf + CAB_PATH_OFFSET; objs[AFTCOL_PATH].data = path; @@ -1685,7 +1715,7 @@ static int com_add_callback(struct afs_callback_arg *aca) objs[AFTCOL_CHUNKS].data = buf + chunks_offset; objs[AFTCOL_CHUNKS].size = aca->query.size - chunks_offset; if (pb && !hs) { /* update pb's hash */ - char old_asc[2 * HASH_SIZE + 1]; + char old_asc[2 * HASH2_SIZE + 1]; unsigned char *old_hash; ret = get_hash_of_row(pb, &old_hash); if (ret < 0) @@ -1790,7 +1820,7 @@ static int add_one_audio_file(const char *path, void *private_data) struct afh_info afhi, *afhi_ptr = NULL; struct osl_row *pb = NULL, *hs = NULL; /* path brother/hash sister */ struct osl_object map, obj = {.data = NULL}, query; - unsigned char hash[HASH_SIZE]; + unsigned char hash[HASH2_SIZE]; bool a_given = SERVER_CMD_OPT_GIVEN(ADD, ALL, pad->lpr); bool f_given = SERVER_CMD_OPT_GIVEN(ADD, FORCE, pad->lpr); bool l_given = SERVER_CMD_OPT_GIVEN(ADD, LAZY, pad->lpr); @@ -1818,11 +1848,11 @@ static int add_one_audio_file(const char *path, void *private_data) ret = mmap_full_file(path, O_RDONLY, &map.data, &map.size, &fd); if (ret < 0) goto out_free; - hash_function(map.data, map.size, hash); + hash2_function(map.data, map.size, hash); /* Check whether the database contains a file with the same hash. */ query.data = hash; - query.size = HASH_SIZE; + query.size = HASH2_SIZE; ret = send_callback_request(hash_sister_callback, &query, get_row_pointer_from_result, &hs); if (ret < 0) @@ -2487,7 +2517,7 @@ static void aft_close(void) PARA_WARNING_LOG("hash lookup failure\n"); current_aft_row = NULL; } else - memcpy(current_hash, p, HASH_SIZE); + memcpy(current_hash, p, HASH2_SIZE); } osl_close_table(audio_file_table, OSL_MARK_CLEAN); audio_file_table = NULL; @@ -2518,10 +2548,12 @@ static int aft_open(const char *dir) 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; - if (ret == -OSL_ERRNO_TO_PARA_ERROR(E_OSL_NOENT)) + if (ret == -OSL_ERRNO_TO_PARA_ERROR(E_OSL_NOENT)) { + PARA_WARNING_LOG("no audio file table\n"); return 1; + } + PARA_NOTICE_LOG("failed to open audio file table\n"); return ret; } @@ -2579,7 +2611,8 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb, ret = get_audio_file_path_of_row(current_aft_row, &path); if (ret < 0) return ret; - status_item_ls_data.path = path; + free(status_item_ls_data.path); + status_item_ls_data.path = para_strdup(path); make_status_items(); return 1; } case AFHI_CHANGE: { @@ -2601,8 +2634,14 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb, /* * These events are rare. We don't bother to check whether the * current status items are affected and simply recreate them - * every time. + * whenever an audio file is open. */ + if (!current_aft_row) + return 0; + ret = get_afhi_of_row(current_aft_row, + &status_item_ls_data.afhi); + if (ret < 0) + return ret; make_status_items(); return 0; } default: