From: Paul Eggert Date: Mon, 7 Aug 2006 21:29:27 +0000 (+0000) Subject: (read_incr_db_01): Check input strings more X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=05805868f26533141b8b02d5a6449965652ef187;p=chaz%2Ftar (read_incr_db_01): Check input strings more carefully. Do not pass arbitrary char values to isspace, as this has undefined behavior. Likewise for assigning arbitrary uintmax_t values to other types. (read_negative_num, read_unsigned_num, read_timespec): New functions, to check input values a bit more carefuly. (read_num): Use read_unsigned_num. New arg MAX_VAL; all callers changed. (read_incr_db_2): Use these new functions. Use a consistent diagnostic for unexpected EOF. (read_directory_file): Do not assign arbitrary uintmax_t value to int. (read_timespec, write_directory_file_entry, write_directory_file): Handle negative time_t values correctly. We don't bother to do this with pre-2 formats, since presumably the time stamps were output incorrectly. --- diff --git a/src/incremen.c b/src/incremen.c index 2fcaa94..7f04f80 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -46,7 +46,7 @@ enum children #define DIR_IS_FOUND(d) ((d)->flags & DIRF_FOUND) #define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW) #define DIR_IS_RENAMED(d) ((d)->flags & DIRF_RENAMED) - + #define DIR_SET_FLAG(d,f) (d)->flags |= (f) #define DIR_CLEAR_FLAG(d,f) (d)->flags &= ~(f) @@ -127,7 +127,7 @@ make_directory (const char *name) directory->name[namelen-1] = 0; return directory; } - + /* Create and link a new directory entry for directory NAME, having a device number DEV and an inode number INO, with NFS indicating whether it is an NFS device and FOUND indicating whether we have @@ -154,7 +154,7 @@ note_directory (char const *name, struct timespec mtime, } else directory->contents = NULL; - + if (! ((directory_table || (directory_table = hash_initialize (0, 0, hash_directory_name, @@ -239,7 +239,7 @@ procdir (char *name_buffer, struct stat *stat_data, { if (DIR_IS_INITED (directory)) return directory; - + /* With NFS, the same file can have two different devices if an NFS directory is mounted in multiple locations, which is relatively common when automounting. @@ -278,7 +278,7 @@ procdir (char *name_buffer, struct stat *stat_data, } else directory->children = CHANGED_CHILDREN; - + DIR_SET_FLAG (directory, DIRF_FOUND); } else @@ -310,7 +310,7 @@ procdir (char *name_buffer, struct stat *stat_data, if (verbose) WARN ((0, 0, _("%s: Directory is new"), quotearg_colon (name_buffer))); - directory->children = + directory->children = (listed_incremental_option || (OLDER_STAT_TIME (*stat_data, m) || (after_date_option @@ -326,11 +326,11 @@ procdir (char *name_buffer, struct stat *stat_data, /* ... except if it was explicitely given in the command line */ && !is_individual_file (name_buffer)) directory->children = NO_CHILDREN; - else if (children == ALL_CHILDREN) + else if (children == ALL_CHILDREN) directory->children = ALL_CHILDREN; DIR_SET_FLAG (directory, DIRF_INIT); - + return directory; } @@ -343,7 +343,7 @@ dumpdir_locate (const char *dump, const char *name) while (*dump) { /* Ignore 'R' (rename) and 'X' (tempname) entries, since they break - alphabetical ordering. + alphabetical ordering. They normally do not occur in dumpdirs from the snapshot files, but this function is also used by purge_directory, which operates on a dumpdir from the archive, hence the need for this test. */ @@ -387,7 +387,7 @@ compare_dirnames (const void *first, const void *second) DIR must be returned by a previous call to savedir(). File names in DIRECTORY->contents must be sorted - alphabetically. + alphabetically. DIRECTORY->contents is replaced with the created template. Each entry is prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */ @@ -461,7 +461,7 @@ scan_directory (char *dir_name, dev_t device) size_t name_length; /* used length in name_buffer */ struct stat stat_data; struct directory *directory; - + if (! dirp) savedir_error (dir_name); @@ -475,7 +475,7 @@ scan_directory (char *dir_name, dev_t device) if (deref_stat (dereference_option, name_buffer, &stat_data)) { stat_diag (name_buffer); - /* FIXME: used to be + /* FIXME: used to be children = CHANGED_CHILDREN; but changed to: */ free (name_buffer); @@ -484,7 +484,7 @@ scan_directory (char *dir_name, dev_t device) } directory = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false); - + if (dirp && directory->children != NO_CHILDREN) { char *entry; /* directory entry being scanned */ @@ -504,7 +504,7 @@ scan_directory (char *dir_name, dev_t device) name_buffer = xrealloc (name_buffer, name_buffer_size + 2); } strcpy (name_buffer + name_length, entry + 1); - + if (excluded_name (name_buffer)) *entry = 'N'; else @@ -515,7 +515,7 @@ scan_directory (char *dir_name, dev_t device) *entry = 'N'; continue; } - + if (S_ISDIR (stat_data.st_mode)) { procdir (name_buffer, &stat_data, device, @@ -523,15 +523,15 @@ scan_directory (char *dir_name, dev_t device) verbose_option); *entry = 'D'; } - + else if (one_file_system_option && device != stat_data.st_dev) *entry = 'N'; else if (*entry == 'Y') /* New entry, skip further checks */; - + /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */ - + else if (OLDER_STAT_TIME (stat_data, m) && (!after_date_option || OLDER_STAT_TIME (stat_data, c))) @@ -541,7 +541,7 @@ scan_directory (char *dir_name, dev_t device) } } } - + free (name_buffer); if (dirp) free (dirp); @@ -570,7 +570,7 @@ rename_handler (void *data, void *proc_data) { struct directory *dir = data; struct obstack *stk = proc_data; - + if (DIR_IS_RENAMED (dir)) { struct directory *prev, *p; @@ -620,7 +620,7 @@ append_incremental_renames (const char *dump) if (directory_table == NULL) return dump; - + obstack_init (&stk); if (dump) { @@ -629,7 +629,7 @@ append_incremental_renames (const char *dump) } else size = 0; - + hash_do_for_each (directory_table, rename_handler, &stk); if (obstack_object_size (&stk) != size) { @@ -661,7 +661,8 @@ read_incr_db_01 (int version, const char *initbuf) { int n; uintmax_t u; - time_t t = u; + time_t sec; + long int nsec; char *buf = 0; size_t bufsize; char *ebuf; @@ -682,41 +683,49 @@ read_incr_db_01 (int version, const char *initbuf) buf = strdup (initbuf); bufsize = strlen (buf) + 1; } - - t = u = (errno = 0, strtoumax (buf, &ebuf, 10)); - if (buf == ebuf || (u == 0 && errno == EINVAL)) - ERROR ((0, 0, "%s:%ld: %s", + + sec = TYPE_MINIMUM (time_t); + nsec = -1; + errno = 0; + u = strtoumax (buf, &ebuf, 10); + if (!errno && TYPE_MAXIMUM (time_t) < u) + errno = ERANGE; + if (errno || buf == ebuf) + ERROR ((0, errno, "%s:%ld: %s", quotearg_colon (listed_incremental_option), lineno, _("Invalid time stamp"))); - else if (t != u) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), - lineno, - _("Time stamp out of range"))); - else if (version == 1) - { - newer_mtime_option.tv_sec = t; - - t = u = (errno = 0, strtoumax (buf, &ebuf, 10)); - if (buf == ebuf || (u == 0 && errno == EINVAL)) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), - lineno, - _("Invalid time stamp"))); - else if (t != u) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), - lineno, - _("Time stamp out of range"))); - newer_mtime_option.tv_nsec = t; - } else { - /* pre-1 incremental format does not contain nanoseconds */ - newer_mtime_option.tv_sec = t; - newer_mtime_option.tv_nsec = 0; + sec = u; + + if (version == 1 && *ebuf) + { + char const *buf_ns = ebuf + 1; + errno = 0; + u = strtoumax (buf_ns, &ebuf, 10); + if (!errno && BILLION <= u) + errno = ERANGE; + if (errno || buf_ns == ebuf) + { + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), + lineno, + _("Invalid time stamp"))); + sec = TYPE_MINIMUM (time_t); + } + else + nsec = u; + } + else + { + /* pre-1 incremental format does not contain nanoseconds */ + nsec = 0; + } } + newer_mtime_option.tv_sec = sec; + newer_mtime_option.tv_nsec = nsec; + while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream))) { @@ -725,65 +734,79 @@ read_incr_db_01 (int version, const char *initbuf) bool nfs = buf[0] == '+'; char *strp = buf + nfs; struct timespec mtime; - + lineno++; - + if (buf[n - 1] == '\n') buf[n - 1] = '\0'; - + if (version == 1) { errno = 0; - mtime.tv_sec = u = strtoumax (strp, &ebuf, 10); - if (!isspace (*ebuf)) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Invalid modification time (seconds)"))); - else if (mtime.tv_sec != u) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Modification time (seconds) out of range"))); + u = strtoumax (strp, &ebuf, 10); + if (!errno && TYPE_MAXIMUM (time_t) < u) + errno = ERANGE; + if (errno || strp == ebuf || *ebuf != ' ') + { + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), lineno, + _("Invalid modification time (seconds)"))); + sec = (time_t) -1; + } + else + sec = u; strp = ebuf; - + errno = 0; - mtime.tv_nsec = u = strtoumax (strp, &ebuf, 10); - if (!isspace (*ebuf)) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Invalid modification time (nanoseconds)"))); - else if (mtime.tv_nsec != u) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Modification time (nanoseconds) out of range"))); + u = strtoumax (strp, &ebuf, 10); + if (!errno && BILLION <= u) + errno = ERANGE; + if (errno || strp == ebuf || *ebuf != ' ') + { + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), lineno, + _("Invalid modification time (nanoseconds)"))); + nsec = -1; + } + else + nsec = u; + mtime.tv_sec = sec; + mtime.tv_nsec = nsec; strp = ebuf; } else memset (&mtime, 0, sizeof mtime); - + errno = 0; - dev = u = strtoumax (strp, &ebuf, 10); - if (!isspace (*ebuf)) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Invalid device number"))); - else if (dev != u) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Device number out of range"))); + u = strtoumax (strp, &ebuf, 10); + if (!errno && TYPE_MAXIMUM (dev_t) < u) + errno = ERANGE; + if (errno || strp == ebuf || *ebuf != ' ') + { + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), lineno, + _("Invalid device number"))); + dev = (dev_t) -1; + } + else + dev = u; strp = ebuf; errno = 0; - ino = u = strtoumax (strp, &ebuf, 10); - if (!isspace (*ebuf)) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Invalid inode number"))); - else if (ino != u) - ERROR ((0, 0, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Inode number out of range"))); + u = strtoumax (strp, &ebuf, 10); + if (!errno && TYPE_MAXIMUM (ino_t) < u) + errno = ERANGE; + if (errno || strp == ebuf || *ebuf != ' ') + { + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), lineno, + _("Invalid inode number"))); + ino = (ino_t) -1; + } + else + ino = u; strp = ebuf; - + strp++; unquote_string (strp); note_directory (strp, mtime, dev, ino, nfs, false, NULL); @@ -810,31 +833,128 @@ read_obstack (FILE *fp, struct obstack *stk, size_t *pcount) } /* Read from file FP a nul-terminated string and convert it to - uintmax_t. Return the resulting value in PVAL. + intmax_t. Return the resulting value in PVAL. Assume '-' has + already been read. + + Throw a fatal error if the string cannot be converted or if the + converted value is less than MIN_VAL. */ + +static void +read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval) +{ + int c; + size_t i; + char buf[INT_BUFSIZE_BOUND (intmax_t)]; + char *ep; + buf[0] = '-'; + + for (i = 1; ISDIGIT (c = getc (fp)); i++) + { + if (i == sizeof buf - 1) + FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file"))); + buf[i] = c; + } + + if (c < 0) + { + if (ferror (fp)) + FATAL_ERROR ((0, errno, _("Read error in snapshot file"))); + else + FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file"))); + } + + buf[i] = 0; + errno = 0; + *pval = strtoimax (buf, &ep, 10); + if (c || errno || *pval < min_val) + FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file"))); +} + +/* Read from file FP a nul-terminated string and convert it to + uintmax_t. Return the resulting value in PVAL. Assume C has + already been read. + + Throw a fatal error if the string cannot be converted or if the + converted value exceeds MAX_VAL. - Throw fatal error if the string cannot be converted. - Return the last character read or EOF on end of file. */ static int -read_num (FILE *fp, uintmax_t *pval) +read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval) { - int c; size_t i; char buf[UINTMAX_STRSIZE_BOUND], *ep; - for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++) + for (i = 0; ISDIGIT (c); i++) { if (i == sizeof buf - 1) FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file"))); buf[i] = c; + c = getc (fp); + } + + if (c < 0) + { + if (ferror (fp)) + FATAL_ERROR ((0, errno, _("Read error in snapshot file"))); + else if (i == 0) + return c; + else + FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file"))); } + buf[i] = 0; + errno = 0; *pval = strtoumax (buf, &ep, 10); - if (*ep) - FATAL_ERROR ((0, 0, _("Unexpected field value in snapshot file"))); + if (c || errno || max_val < *pval) + FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file"))); return c; -} +} + +/* Read from file FP a nul-terminated string and convert it to + uintmax_t. Return the resulting value in PVAL. + + Throw a fatal error if the string cannot be converted or if the + converted value exceeds MAX_VAL. + + Return the last character read or EOF on end of file. */ + +static int +read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval) +{ + return read_unsigned_num (getc (fp), fp, max_val, pval); +} + +/* Read from FP two NUL-terminated strings representing a struct + timespec. Return the resulting value in PVAL. + + Throw a fatal error if the string cannot be converted. */ + +static void +read_timespec (FILE *fp, struct timespec *pval) +{ + int c = getc (fp); + intmax_t i; + uintmax_t u; + + if (c == '-') + { + read_negative_num (fp, TYPE_MINIMUM (time_t), &i); + c = 0; + pval->tv_sec = i; + } + else + { + c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u); + pval->tv_sec = u; + } + + if (c || read_num (fp, BILLION - 1, &u)) + FATAL_ERROR ((0, 0, "%s: %s", + quotearg_colon (listed_incremental_option), + _("Unexpected EOF in snapshot file"))); + pval->tv_nsec = u; +} /* Read incremental snapshot format 2 */ static void @@ -842,28 +962,10 @@ read_incr_db_2 () { uintmax_t u; struct obstack stk; - - obstack_init (&stk); - if (read_num (listed_incremental_stream, &u)) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Error reading time stamp"))); - newer_mtime_option.tv_sec = u; - if (newer_mtime_option.tv_sec != u) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Time stamp out of range"))); + obstack_init (&stk); - if (read_num (listed_incremental_stream, &u)) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Error reading time stamp"))); - newer_mtime_option.tv_nsec = u; - if (newer_mtime_option.tv_nsec != u) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Time stamp out of range"))); + read_timespec (listed_incremental_stream, &newer_mtime_option); for (;;) { @@ -874,43 +976,21 @@ read_incr_db_2 () char *name; char *content; size_t s; - - if (read_num (listed_incremental_stream, &u)) + + if (read_num (listed_incremental_stream, 1, &u)) return; /* Normal return */ nfs = u; - - if (read_num (listed_incremental_stream, &u)) - break; - mtime.tv_sec = u; - if (mtime.tv_sec != u) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Modification time (seconds) out of range"))); - - if (read_num (listed_incremental_stream, &u)) - break; - mtime.tv_nsec = u; - if (mtime.tv_nsec != u) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Modification time (nanoseconds) out of range"))); - if (read_num (listed_incremental_stream, &u)) + read_timespec (listed_incremental_stream, &mtime); + + if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u)) break; dev = u; - if (dev != u) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Device number out of range"))); - if (read_num (listed_incremental_stream, &u)) + if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u)) break; ino = u; - if (ino != u) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Inode number out of range"))); if (read_obstack (listed_incremental_stream, &stk, &s)) break; @@ -921,16 +1001,16 @@ read_incr_db_2 () ; if (getc (listed_incremental_stream) != 0) FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), + quotearg_colon (listed_incremental_option), _("Missing record terminator"))); - + content = obstack_finish (&stk); note_directory (name, mtime, dev, ino, nfs, false, content); obstack_free (&stk, content); } FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Unexpected EOF"))); + quotearg_colon (listed_incremental_option), + _("Unexpected EOF in snapshot file"))); } /* Read incremental snapshot file (directory file). @@ -967,7 +1047,7 @@ read_directory_file (void) if (0 < getline (&buf, &bufsize, listed_incremental_stream)) { char *ebuf; - int incremental_version; + uintmax_t incremental_version; if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0) { @@ -978,7 +1058,7 @@ read_directory_file (void) if (!*ebuf) ERROR((1, 0, _("Bad incremental file format"))); - incremental_version = (errno = 0, strtoumax (ebuf+1, &ebuf, 10)); + incremental_version = strtoumax (ebuf + 1, NULL, 10); } else incremental_version = 0; @@ -993,12 +1073,12 @@ read_directory_file (void) case TAR_INCREMENTAL_VERSION: read_incr_db_2 (); break; - + default: - ERROR ((1, 0, _("Unsupported incremental format version: %d"), + ERROR ((1, 0, _("Unsupported incremental format version: %"PRIuMAX), incremental_version)); } - + } if (ferror (listed_incremental_stream)) @@ -1022,7 +1102,9 @@ write_directory_file_entry (void *entry, void *data) s = DIR_IS_NFS (directory) ? "1" : "0"; fwrite (s, 2, 1, fp); - s = umaxtostr (directory->mtime.tv_sec, buf); + s = (TYPE_SIGNED (time_t) + ? imaxtostr (directory->mtime.tv_sec, buf) + : umaxtostr (directory->mtime.tv_sec, buf)); fwrite (s, strlen (s) + 1, 1, fp); s = umaxtostr (directory->mtime.tv_nsec, buf); fwrite (s, strlen (s) + 1, 1, fp); @@ -1065,7 +1147,9 @@ write_directory_file (void) fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION, TAR_INCREMENTAL_VERSION); - s = umaxtostr (start_time.tv_sec, buf); + s = (TYPE_SIGNED (time_t) + ? imaxtostr (start_time.tv_sec, buf) + : umaxtostr (start_time.tv_sec, buf)); fwrite (s, strlen (s) + 1, 1, fp); s = umaxtostr (start_time.tv_nsec, buf); fwrite (s, strlen (s) + 1, 1, fp); @@ -1138,7 +1222,7 @@ dumpdir_ok (char *dumpdir) char *p; int has_tempdir = 0; int expect = 0; - + for (p = dumpdir; *p; p += strlen (p) + 1) { if (expect && *p != expect) @@ -1160,7 +1244,7 @@ dumpdir_ok (char *dumpdir) else has_tempdir = 1; break; - + case 'R': if (p[1] == 0) { @@ -1175,14 +1259,14 @@ dumpdir_ok (char *dumpdir) } expect = 'T'; break; - + case 'T': if (expect != 'T') { ERROR ((0, 0, _("Malformed dumpdir: 'T' not preceeded by 'R'"))); return false; - } + } if (p[1] == 0 && !has_tempdir) { ERROR ((0, 0, @@ -1191,7 +1275,7 @@ dumpdir_ok (char *dumpdir) } expect = 0; break; - + case 'N': case 'Y': case 'D': @@ -1216,7 +1300,7 @@ dumpdir_ok (char *dumpdir) return true; } - + /* Examine the directories under directory_name and delete any files that were not there at the time of the back-up. */ static bool @@ -1225,7 +1309,7 @@ try_purge_directory (char const *directory_name) char *current_dir; char *cur, *arc, *p; char *temp_stub = NULL; - + if (!is_dumpdir (¤t_stat_info)) return false; @@ -1239,13 +1323,13 @@ try_purge_directory (char const *directory_name) /* Verify if dump directory is sane */ if (!dumpdir_ok (current_stat_info.dumpdir)) return false; - + /* Process renames */ for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1) { if (*arc == 'X') { -#define TEMP_DIR_TEMPLATE "tar.XXXXXX" +#define TEMP_DIR_TEMPLATE "tar.XXXXXX" size_t len = strlen (arc + 1); temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE); memcpy (temp_stub, arc + 1, len); @@ -1273,7 +1357,7 @@ try_purge_directory (char const *directory_name) src = temp_stub; else if (*dst == 0) dst = temp_stub; - + if (!rename_directory (src, dst)) { free (temp_stub); @@ -1286,7 +1370,7 @@ try_purge_directory (char const *directory_name) } free (temp_stub); - + /* Process deletes */ p = NULL; for (cur = current_dir; *cur; cur += strlen (cur) + 1) @@ -1334,7 +1418,7 @@ try_purge_directory (char const *directory_name) } } free (p); - + free (current_dir); return true; } @@ -1345,7 +1429,7 @@ purge_directory (char const *directory_name) if (!try_purge_directory (directory_name)) skip_member (); } - + void list_dumpdir (char *buffer, size_t size) {