X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=aft.c;h=0c4c93280a3f409b7a791aa0b33c5e82369da732;hp=aebb3efb0c0ec4f7f99f94dded4636b76e2ec5d1;hb=a85b3b947174c64ce06b4d6e438677055bf3f1ae;hpb=7af252cbfe13650ee0a6ae18abe22422527a70c1 diff --git a/aft.c b/aft.c index aebb3efb..0c4c9328 100644 --- a/aft.c +++ b/aft.c @@ -320,8 +320,8 @@ enum afhi_offsets { CHUNKS_TOTAL_OFFSET = 20, /** The length of the audio file header (4 bytes). */ HEADER_LEN_OFFSET = 24, - /** Was: The start of the audio file header (4 bytes). */ - AFHI_UNUSED2_OFFSET = 28, + /** Size of the largest chunk in bytes. (4 bytes). */ + AFHI_MAX_CHUNK_SIZE_OFFSET = 28, /** The seconds part of the chunk time (4 bytes). */ CHUNK_TV_TV_SEC_OFFSET = 32, /** The microseconds part of the chunk time (4 bytes). */ @@ -361,7 +361,7 @@ static void save_afhi(struct afh_info *afhi, char *buf) write_u8(buf + AFHI_CHANNELS_OFFSET, afhi->channels); write_u32(buf + CHUNKS_TOTAL_OFFSET, afhi->chunks_total); write_u32(buf + HEADER_LEN_OFFSET, afhi->header_len); - write_u32(buf + AFHI_UNUSED2_OFFSET, 0); + write_u32(buf + AFHI_MAX_CHUNK_SIZE_OFFSET, afhi->max_chunk_size); write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec); write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec); p = buf + AFHI_INFO_STRING_OFFSET; @@ -374,6 +374,7 @@ static void save_afhi(struct afh_info *afhi, char *buf) sprintf(p, "%s", afhi->tags.comment); } +/* does not load the chunk table */ static void load_afhi(const char *buf, struct afh_info *afhi) { afhi->seconds_total = read_u32(buf + AFHI_SECONDS_TOTAL_OFFSET); @@ -383,6 +384,7 @@ static void load_afhi(const char *buf, struct afh_info *afhi) afhi->channels = read_u8(buf + AFHI_CHANNELS_OFFSET); afhi->chunks_total = read_u32(buf + CHUNKS_TOTAL_OFFSET); afhi->header_len = read_u32(buf + HEADER_LEN_OFFSET); + afhi->max_chunk_size = read_u32(buf + AFHI_MAX_CHUNK_SIZE_OFFSET); afhi->chunk_tv.tv_sec = read_u32(buf + CHUNK_TV_TV_SEC_OFFSET); afhi->chunk_tv.tv_usec = read_u32(buf + CHUNK_TV_TV_USEC_OFFSET); afhi->techinfo = (char *)buf + AFHI_INFO_STRING_OFFSET; @@ -393,42 +395,37 @@ static void load_afhi(const char *buf, struct afh_info *afhi) afhi->tags.comment = afhi->tags.album + strlen(afhi->tags.album) + 1; } +/* Only used for saving the chunk table, but not for loading. */ static unsigned sizeof_chunk_table(struct afh_info *afhi) { - if (!afhi) + if (!afhi || !afhi->chunk_table) return 0; return 4 * (afhi->chunks_total + 1); } -static uint32_t save_chunk_table(struct afh_info *afhi, char *buf) +static void save_chunk_table(struct afh_info *afhi, char *buf) { - int i; - uint32_t max = 0, old = 0; - - for (i = 0; i <= afhi->chunks_total; i++) { - uint32_t val = afhi->chunk_table[i]; - write_u32(buf + 4 * i, val); - /* - * If the first chunk is the header, do not consider it for the - * calculation of the largest chunk size. - */ - if (i == 0 || (i == 1 && afhi->header_len > 0)) { - old = val; - continue; - } - max = PARA_MAX(max, val - old); - old = val; - } - return max; + uint32_t n; + + if (!afhi->chunk_table) + return; + for (n = 0; n <= afhi->chunks_total; n++) + write_u32(buf + 4 * n, afhi->chunk_table[n]); } -static void load_chunk_table(struct afh_info *afhi, char *buf) +static void load_chunk_table(struct afh_info *afhi, const struct osl_object *ct) { int i; + size_t sz; - afhi->chunk_table = para_malloc(sizeof_chunk_table(afhi)); - for (i = 0; i <= afhi->chunks_total; i++) - afhi->chunk_table[i] = read_u32(buf + 4 * i); + if (!ct->data || ct->size < 4) { + afhi->chunk_table = NULL; + return; + } + sz = PARA_MIN(((size_t)afhi->chunks_total + 1) * 4, ct->size) + 1; + afhi->chunk_table = para_malloc(sz); + for (i = 0; i <= afhi->chunks_total && i * 4 + 3 < ct->size; i++) + afhi->chunk_table[i] = read_u32(ct->data + 4 * i); } /** @@ -594,6 +591,10 @@ static int get_hash_of_row(const struct osl_row *row, unsigned char **hash) * * \return The return value of the underlying call to osl_get_object(). * + * After the call the members of the afhi structure point to mapped memory + * which is owned by the osl table, Hence the caller must not attempt to free + * this memory by calling \ref clear_afhi(). + * * \sa get_chunk_table_of_row(). */ int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi) @@ -623,7 +624,13 @@ static int save_afd(struct audio_file_data *afd) goto err; buf = shm_afd; buf += sizeof(*afd); - afd->max_chunk_size = save_chunk_table(&afd->afhi, buf); + save_chunk_table(&afd->afhi, buf); + if (afd->afhi.max_chunk_size == 0) { /* v0.5.x on-disk afhi */ + set_max_chunk_size(&afd->afhi); + PARA_NOTICE_LOG("max chunk size unset, re-add required\n"); + } else + PARA_INFO_LOG("using max chunk size from afhi\n"); + afd->max_chunk_size = afd->afhi.max_chunk_size; *(struct audio_file_data *)shm_afd = *afd; shm_detach(shm_afd); return shmid; @@ -648,14 +655,22 @@ int load_afd(int shmid, struct audio_file_data *afd) { void *shm_afd; int ret; + struct osl_object obj; ret = shm_attach(shmid, ATTACH_RO, &shm_afd); if (ret < 0) return ret; + ret = shm_size(shmid, &obj.size); + if (ret < 0) + goto detach; *afd = *(struct audio_file_data *)shm_afd; - load_chunk_table(&afd->afhi, shm_afd + sizeof(*afd)); + obj.data = shm_afd + sizeof(*afd); + obj.size -= sizeof(*afd); + load_chunk_table(&afd->afhi, &obj); + ret = 1; +detach: shm_detach(shm_afd); - return 1; + return ret; } static int get_local_time(uint64_t *seconds, char *buf, size_t size, @@ -684,7 +699,7 @@ static int get_local_time(uint64_t *seconds, char *buf, size_t size, /* * If the given time is more than six month away from the current time, * we print only the year. The additional space character in the format - * string below makes the formated date align nicely with dates that + * string below makes the formatted date align nicely with dates that * contain the time (those written by the above strftime() statement). */ if (!strftime(buf, size, "%b %e %Y", tm)) @@ -805,7 +820,11 @@ static int print_chunk_table(struct ls_data *d, struct para_buffer *b) (long unsigned) d->afhi.chunk_tv.tv_usec ); buf = chunk_table_obj.data; - for (i = 0; i <= d->afhi.chunks_total; i++) + for ( + i = 0; + i <= d->afhi.chunks_total && 4 * i + 3 < chunk_table_obj.size; + i++ + ) para_printf(b, "%u ", (unsigned) read_u32(buf + 4 * i)); para_printf(b, "\n"); ret = 1; @@ -891,7 +910,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, last_played_time, bn? bn : "?"); } - write_filename_items(b, d->path, lls_opt_given(r_b) > 0); + 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); ret = write_attribute_items(b, att_buf, afsi); @@ -915,6 +934,8 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, 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", + 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); @@ -961,8 +982,7 @@ out: static int make_status_items(void) { const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS); - char *argv[] = {"ls", "--path", "--admissible", - "--listing-mode=verbose"}; + char *argv[] = {"ls", "--admissible", "--listing-mode=verbose"}; struct ls_options opts = {.mode = LS_MODE_VERBOSE}; struct para_buffer pb = {.max_size = shm_get_shmmax() - 1}; time_t current_time; @@ -1040,8 +1060,15 @@ again: 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) - return ret; + if (ret < 0) { + if (!afh_supports_dynamic_chunks(d->afsi.audio_format_id)) + return ret; + PARA_INFO_LOG("no chunk table for %s\n", d->path); + chunk_table_obj.data = NULL; + chunk_table_obj.size = 0; + } 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); if (ret < 0) goto out; @@ -1058,7 +1085,7 @@ again: 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.data); + load_chunk_table(&afd->afhi, &chunk_table_obj); aced.aft_row = current_aft_row; aced.old_afsi = &d->afsi; /* @@ -1071,7 +1098,8 @@ again: ret = save_afd(afd); out: free(afd->afhi.chunk_table); - osl_close_disk_object(&chunk_table_obj); + if (chunk_table_obj.data) + osl_close_disk_object(&chunk_table_obj); if (ret < 0) { PARA_ERROR_LOG("%s: %s\n", d->path, para_strerror(-ret)); ret = score_delete(current_aft_row); @@ -1211,7 +1239,7 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts) { int ret, i; struct ls_options *options = ls_opts; - bool basename_given = SERVER_CMD_OPT_GIVEN(LS, BASENAME, options->lpr) > 0; + bool basename_given = SERVER_CMD_OPT_GIVEN(LS, BASENAME, options->lpr); struct ls_data *d; struct ls_widths *w; unsigned short num_digits; @@ -1673,6 +1701,7 @@ static int com_add_callback(struct afs_callback_arg *aca) &objs[AFTCOL_AFHI])); if (ret < 0) goto out; + /* truncate the file to size zero if there is no chunk table */ ret = osl(osl_update_object(audio_file_table, row, AFTCOL_CHUNKS, &objs[AFTCOL_CHUNKS])); if (ret < 0) @@ -2113,7 +2142,9 @@ static int copy_selector_info(__a_unused struct osl_table *table, ret = get_afsi_object_of_row(row, &target_afsi_obj); if (ret < 0) return ret; - load_afsi(&target_afsi, &target_afsi_obj); + ret = load_afsi(&target_afsi, &target_afsi_obj); + if (ret < 0) + return ret; old_afsi = target_afsi; if (cad->copy_all || y_given) target_afsi.lyrics_id = cad->source_afsi.lyrics_id;