+static size_t temp_write_cb(const void *ptr, size_t size, size_t nmemb,
+ FLAC__IOHandle handle)
+{
+ int ret, fd = *(int *)handle;
+ size_t n = size * nmemb; /* FIXME: possible overflow */
+
+ ret = write_all(fd, ptr, n);
+
+ /*
+ * libflac expects POSIX semantics: If an error occurs, or the end of
+ * the file is reached, the return value is a short item count or zero.
+ */
+ if (ret < 0) {
+ PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ return 0;
+ }
+ return nmemb;
+}
+
+/* only the write callback needs to be supplied for writing the temp file. */
+static const FLAC__IOCallbacks temp_callbacks = {
+ .write = temp_write_cb,
+};
+
+static int flac_write_chain(FLAC__Metadata_Chain *chain,
+ struct private_flac_afh_data *pfad, int fd)
+{
+ FLAC__bool ok;
+
+ ok = FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain,
+ false /* no padding*/, pfad,
+ meta_callbacks, &fd, temp_callbacks);
+ if (!ok) {
+ FLAC__Metadata_ChainStatus st;
+ st = FLAC__metadata_chain_status(chain);
+ PARA_ERROR_LOG("chain status: %u\n", st);
+ if (st == FLAC__METADATA_CHAIN_STATUS_READ_ERROR)
+ PARA_ERROR_LOG("read error\n");
+ return -E_FLAC_WRITE_CHAIN;
+ }
+ return 1;
+}
+
+static int flac_rewrite_tags(const char *map, size_t map_bytes,
+ struct taginfo *tags, int fd, __a_unused const char *filename)
+{
+ int ret;
+ FLAC__Metadata_Chain *chain;
+ FLAC__Metadata_Iterator *iter;
+ FLAC__StreamMetadata *b = NULL;
+ FLAC__bool ok;
+ struct private_flac_afh_data *pfad = para_calloc(sizeof(*pfad));
+
+ pfad->map = map;
+ pfad->map_bytes = map_bytes;
+ pfad->fpos = 0;
+
+ ret = flac_init_meta(pfad, &chain, &iter);
+ if (ret < 0)
+ goto free_pfad;
+ for (ok = true; ok; ok = FLAC__metadata_iterator_next(iter)) {
+ b = FLAC__metadata_iterator_get_block(iter);
+ assert(b);
+ if (b->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+ break;
+ b = NULL;
+ }
+ ret = -E_FLAC_REPLACE_COMMENT;
+ if (!b)
+ goto out;
+ ret = flac_replace_vorbis_comments(chain, b, tags);
+ if (ret < 0)
+ goto out;
+ ret = flac_write_chain(chain, pfad, fd);
+out:
+ FLAC__metadata_iterator_delete(iter);
+ FLAC__metadata_chain_delete(chain);
+free_pfad:
+ free(pfad);
+ return ret;
+}
+
+static const char * const flac_suffixes[] = {"flac", NULL};