+ arg = OPT_STRING_VAL(ALBUM);
+ if (tag_needs_update(OPT_GIVEN(ALBUM), tags->album, arg)) {
+ free(tags->album);
+ tags->album = para_strdup(arg);
+ modified = true;
+ }
+ arg = OPT_STRING_VAL(COMMENT);
+ if (tag_needs_update(OPT_GIVEN(COMMENT), tags->comment, arg)) {
+ free(tags->comment);
+ tags->comment = para_strdup(arg);
+ modified = true;
+ }
+ if (!modified) {
+ PARA_WARNING_LOG("no modifications necessary\n");
+ return 0;
+ }
+ /*
+ * mkstmp() creates the temporary file with permissions 0600, but we
+ * like it to have the same permissions as the original file, so we
+ * have to get this information.
+ */
+ if (fstat(input_fd, &sb) < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ PARA_ERROR_LOG("failed to fstat fd %d (%s)\n", input_fd, name);
+ return ret;
+ }
+ tmp_name = make_message("%s.XXXXXX", name);
+ ret = mkstemp(tmp_name);
+ if (ret < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ PARA_ERROR_LOG("could not create temporary file\n");
+ goto out;
+ }
+ output_fd = ret;
+ if (fchmod(output_fd, sb.st_mode) < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ PARA_ERROR_LOG("failed to fchmod fd %d (%s)\n", output_fd,
+ tmp_name);
+ goto out;
+ }
+ ret = afh_rewrite_tags(audio_format_id, map, map_size, tags, output_fd,
+ tmp_name);
+ if (ret < 0)
+ goto out;
+ if (OPT_GIVEN(BACKUP)) {
+ char *backup_name = make_message("%s~", name);
+ ret = xrename(name, backup_name);
+ free(backup_name);
+ if (ret < 0)
+ goto out;
+ }
+ ret = xrename(tmp_name, name);
+ if (ret < 0)
+ goto out;
+ if (OPT_GIVEN(PRESERVE)) {
+ struct timespec times[2]; /* [0]: atime, [1]: mtime */
+ times[0].tv_nsec = UTIME_OMIT;
+ times[1] = sb.st_mtim;
+ /*
+ * We might well have written a file of identical size. If we
+ * keep the mtime as well, we might fool backup applications
+ * like rsync which skip files whose size and mtime haven't
+ * changed. So we change the mtime slightly.
+ */
+ times[1].tv_sec++;
+ if (futimens(output_fd, times) < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ goto out;
+ }
+ }
+out:
+ if (ret < 0 && output_fd >= 0)
+ unlink(tmp_name); /* ignore errors */
+ free(tmp_name);
+ if (output_fd >= 0)
+ close(output_fd);
+ return ret;
+}
+
+static void print_info(int audio_format_num, struct afh_info *afhi)
+{
+ char *msg;
+
+ afh_get_afhi_txt(audio_format_num, afhi, &msg);
+ printf("%s", msg);
+ free(msg);
+}
+
+static void print_chunk_table(struct afh_info *afhi, int audio_format_id,
+ const void *map, size_t mapsize)
+{
+ int i, ret;
+ void *ctx = NULL;
+
+ for (i = 0; i < afhi->chunks_total; i++) {