Truncate overlong tag info and replace newlines by spaces.
authorAndre Noll <maan@systemlinux.org>
Wed, 27 May 2009 17:16:54 +0000 (19:16 +0200)
committerAndre Noll <maan@systemlinux.org>
Wed, 27 May 2009 17:16:54 +0000 (19:16 +0200)
The tag info which is computed by the audio format handlers and stored
in the audio file table is read into a fixed-size buffer by the audio
file selector in open_and_update_audio_file(), passed to the server
process and then sent to the client via the stat command. It is not
interpreted at all during this process. In particular, it is not
essential for correctly streaming the audio file.

Vorbis comments and id3v2 tags have no size limit and may contain
arbitrary data which may lead to the following twi problems:

- As noted by Gerrit Renker, if the tag info is too long
to fit into the fixed-size buffer, the current code skips
the audio file and removes it from the list of currently
admissible files. So para_server fails to stream such files.

- If the tag info contains newlines, these are included
verbatim in the status output which may confuse para_audiod.

This patch truncates the tag info string if it does not fit into the
4K buffer and replaces newlines by spaces. This is a bit ugly but
avoids both of the above problems. It's still possible to retrieve
the complete tag info via the "ls -lv" command.

aft.c

diff --git a/aft.c b/aft.c
index 3283dda82d309769fa569d7ab6b32b299d368b4f..995c7552129512c6e2dc6228c165779c9e7979a0 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -980,12 +980,66 @@ void make_empty_status_items(char *buf)
        );
 }
 
        );
 }
 
+static void fixup_taginfo(char *begin, char *end)
+{
+       char *p = begin;
+
+       for (;;) {
+               p = strchr(p, '\n');
+               if (!p)
+                       break;
+               if (p >= end - 1)
+                       break;
+               *p = ' ';
+               p++;
+       }
+}
+
+/* crap, remove this ASAP. */
+static int fixup_info_string(char *info_string)
+{
+       char *t1, *t2, *end;
+
+       if (strncmp(info_string, "audio_file_info:", 16))
+               return -ERRNO_TO_PARA_ERROR(EINVAL);
+       t1 = strstr(info_string, "\ntaginfo1:");
+       if (!t1)
+               return -ERRNO_TO_PARA_ERROR(EINVAL);
+       t2 = strstr(info_string, "\ntaginfo2: ");
+       if (!t2)
+               return -ERRNO_TO_PARA_ERROR(EINVAL);
+
+       end = t2 + strlen(t2) + 1;
+       fixup_taginfo(info_string + 16, t1);
+       fixup_taginfo(t1 + 10, t2);
+       fixup_taginfo(t2 + 10, end);
+
+       if (t1 - info_string < 80 && t2 - t1 < 80 && end - t2 < 80)
+               return 0;
+       if (t1 - info_string >= 80) {
+               memmove(info_string + 80, t1, end - t1);
+               t1 = info_string + 80;
+               t2 -= t1 - info_string - 80;
+               end -= t1 - info_string - 80;
+       }
+       if (t2 - t1 >= 80) {
+               memmove(t1 + 80, t2, end - t2);
+               end -= t2 - t1 - 80;
+               t2 = t1 + 80;
+       }
+       if (end - t2 >= 80) {
+               t2[78] = '\n';
+               t2[79] = '\0';
+       }
+       return 1;
+}
+
 static int make_status_items(struct audio_file_data *afd,
                struct afs_info *afsi, char *path, long score,
                HASH_TYPE *hash)
 {
        struct ls_data d = {
 static int make_status_items(struct audio_file_data *afd,
                struct afs_info *afsi, char *path, long score,
                HASH_TYPE *hash)
 {
        struct ls_data d = {
-               .afhi = afd->afhi, /* struct copy */
+               .afhi = afd->afhi,
                .afsi = *afsi,
                .path = path,
                .score = score,
                .afsi = *afsi,
                .path = path,
                .score = score,
@@ -999,6 +1053,12 @@ static int make_status_items(struct audio_file_data *afd,
        time_t current_time;
        int ret;
 
        time_t current_time;
        int ret;
 
+       ret = fixup_info_string(afd->afhi.info_string);
+       if (ret < 0) {
+               PARA_WARNING_LOG("ignoring invalid tag info\n");
+               afd->afhi.info_string[0] = '\0';
+       } else if (ret)
+               PARA_NOTICE_LOG("truncated overlong tag info\n");
        time(&current_time);
        ret = print_list_item(&d, &opts, &pb, current_time); /* frees info string */
        afd->afhi.info_string = NULL;
        time(&current_time);
        ret = print_list_item(&d, &opts, &pb, current_time); /* frees info string */
        afd->afhi.info_string = NULL;