summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Howard <[email protected]>2025-06-18 14:50:28 -0400
committerSimon Howard <[email protected]>2025-06-19 11:57:34 -0400
commite58cc811cc0161ca808a13b8aafda5123097f3c3 (patch)
treef35548d9804779fd40824a6d6380f2b2f9dbaadf
parent51a2a84bcd7bd10ff53cf87b58e4b3ec89011df1 (diff)
downloadengrampa-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.c91
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';