diff options
author | Simon Howard <[email protected]> | 2025-06-18 14:50:28 -0400 |
---|---|---|
committer | Simon Howard <[email protected]> | 2025-06-19 11:57:34 -0400 |
commit | e58cc811cc0161ca808a13b8aafda5123097f3c3 (patch) | |
tree | f35548d9804779fd40824a6d6380f2b2f9dbaadf | |
parent | 51a2a84bcd7bd10ff53cf87b58e4b3ec89011df1 (diff) | |
download | engrampa-e58cc811cc0161ca808a13b8aafda5123097f3c3.tar.bz2 engrampa-e58cc811cc0161ca808a13b8aafda5123097f3c3.tar.xz |
lha: Fix crash, parse lha list output correctly
The output from the `lha` list archive command is eclectic and
inconsistent, and engrampa was actually crashing when opening certain
archives (eg. lha_os2_208/h3_subdir.lzh in the Lhasa test suite). But this
also fixes the list parsing more generally. With this change, engrampa
now appears to successfully open all of the .lzh files in the Lhasa test
suite correctly without crashing.
The first field in lha's list output either contains Unix permissions or
an OS name in [brackets]. There was already hard-coded support for
[MS-DOS], [generic], [unknown] and [Amiga], but other OS names were not
handled properly. This is now fixed, with an approach that is mindful of
the fact that the OS name can contain spaces.
Empty value (whitespace) in the UID/GID column is also handled
correctly. This was partially working because of the aforementioned
special-casing, but now is fixed more generally.
-rw-r--r-- | src/fr-command-lha.c | 91 |
1 files changed, 37 insertions, 54 deletions
diff --git a/src/fr-command-lha.c b/src/fr-command-lha.c index 22fd61d..2535412 100644 --- a/src/fr-command-lha.c +++ b/src/fr-command-lha.c @@ -96,8 +96,8 @@ static char ** split_line_lha (char *line) { char **fields; - int n_fields = 7; - const char *scan; + int n_fields = 8; + const char *scan, *field_end; int i; fields = g_new0 (char *, n_fields + 1); @@ -105,66 +105,48 @@ split_line_lha (char *line) i = 0; - if (strncmp (line, "[MS-DOS]", 8) == 0) { - fields[i++] = g_strdup (""); - fields[i++] = g_strdup (""); - line += strlen ("[MS-DOS]"); - } - else if (strncmp (line, "[generic]", 9) == 0) { - fields[i++] = g_strdup (""); - fields[i++] = g_strdup (""); - line += strlen ("[generic]"); - } - else if (strncmp (line, "[unknown]", 9) == 0) { - fields[i++] = g_strdup (""); - fields[i++] = g_strdup (""); - line += strlen ("[unknown]"); - } - else if (strncmp (line, "[Amiga]", 7) == 0) { - fields[i++] = g_strdup (""); - fields[i++] = g_strdup (""); - line += strlen ("[Amiga]"); - } - + /* First column either contains Unix permissions or OS type, depending + * on what generated the archive. The OS type is enclosed in [brackets] + * and may include a space. */ scan = eat_spaces (line); - for (; i < n_fields; i++) { - const char *field_end; - - if (NULL != (field_end = strchr (scan, ' '))) { - fields[i] = g_strndup (scan, field_end - scan); - scan = eat_spaces (field_end); + if (scan[0] == '[') { + field_end = strchr (scan, ']'); + if (field_end != NULL) { + ++field_end; } + } else { + field_end = NULL; } - return fields; -} - -static const char * -get_last_field_lha (char *line) -{ - int i; - const char *field; - int n = 7; - - if (strncmp (line, "[MS-DOS]", 8) == 0) - n--; + if (field_end == NULL) { + field_end = strchr (scan, ' '); + if (field_end == NULL) { + field_end = scan + strlen(scan); + } + } - if (strncmp (line, "[generic]", 9) == 0) - n--; + fields[i++] = g_strndup (scan, field_end - scan); + scan = field_end; - if (strncmp (line, "[unknown]", 9) == 0) - n--; + /* Second column contains Unix UID/GID, but if the archive was not + * made on a Unix system it will be empty. Insert a dummy value so + * we get a consistent result. */ + if (g_str_has_prefix (scan, " ")) { + fields[i++] = g_strdup(""); + } - if (strncmp (line, "[Amiga]", 7) == 0) - n--; + scan = eat_spaces (scan); + for (; i < n_fields; i++) { + field_end = strchr (scan, ' '); + if (field_end == NULL) { + field_end = scan + strlen(scan); + } - field = eat_spaces (line); - for (i = 0; i < n; i++) { - field = strchr (field, ' '); - field = eat_spaces (field); + fields[i] = g_strndup (scan, field_end - scan); + scan = eat_spaces (field_end); } - return field; + return fields; } static void @@ -185,11 +167,10 @@ process_line (char *line, fdata->modified = mktime_from_string (fields[4], fields[5], fields[6]); - g_strfreev (fields); /* Full path */ - name_field = get_last_field_lha (line); + name_field = fields[7]; if (name_field && *name_field == '/') { fdata->full_path = g_strdup (name_field); @@ -199,6 +180,8 @@ process_line (char *line, fdata->original_path = fdata->full_path + 1; } + g_strfreev (fields); + fdata->link = NULL; fdata->dir = line[0] == 'd'; |