From f3adf4b52d600e699c5d826866cb5f4c520bb5a3 Mon Sep 17 00:00:00 2001 From: mm Date: Tue, 20 Dec 2011 20:34:02 +0000 Subject: Sync libarchive with vendor branch release/2.8: 3730: Fix issue 174 (Windows path names, not relevant for FreeBSD) 3734: Merge r1989: archive_clear_error should set errno to 0. 3735: Merge r3247 from trunk: Clear errors before returning from archive_read_support_format_all() 3799: Check the position before dereferencing the pointer. This avoids dereferencing one byte past the end of a string 3824: Merge r3823 from trunk for issue 199 (hang in iso9660 reading) Obtained from: http://code.google.com/p/libarchive MFC after: 2 weeks --- lib/libarchive/archive_read_support_format_all.c | 10 +- .../archive_read_support_format_iso9660.c | 10 +- lib/libarchive/archive_string.c | 2 +- lib/libarchive/archive_util.c | 1 + lib/libarchive/archive_write_disk.c | 104 +++++++++++++++++++-- 5 files changed, 114 insertions(+), 13 deletions(-) diff --git a/lib/libarchive/archive_read_support_format_all.c b/lib/libarchive/archive_read_support_format_all.c index 69d16fc..e57cd43 100644 --- a/lib/libarchive/archive_read_support_format_all.c +++ b/lib/libarchive/archive_read_support_format_all.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2011 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,5 +39,13 @@ archive_read_support_format_all(struct archive *a) archive_read_support_format_tar(a); archive_read_support_format_xar(a); archive_read_support_format_zip(a); + + /* Note: We always return ARCHIVE_OK here, even if some of the + * above return ARCHIVE_WARN. The intent here is to enable + * "as much as possible." Clients who need specific + * compression should enable those individually so they can + * verify the level of support. */ + /* Clear any warning messages set by the above functions. */ + archive_clear_error(a); return (ARCHIVE_OK); } diff --git a/lib/libarchive/archive_read_support_format_iso9660.c b/lib/libarchive/archive_read_support_format_iso9660.c index 6d8d304..f014eb3 100644 --- a/lib/libarchive/archive_read_support_format_iso9660.c +++ b/lib/libarchive/archive_read_support_format_iso9660.c @@ -302,6 +302,8 @@ struct file_info { struct file_info *first; struct file_info **last; } rede_files; + /* To check a ininity loop. */ + struct file_info *loop_by; }; struct heap_queue { @@ -2699,8 +2701,14 @@ rede_add_entry(struct file_info *file) struct file_info *re; re = file->parent; - while (re != NULL && !re->re) + while (re != NULL && !re->re) { + /* Sanity check to prevent a infinity loop + * cause by a currupted iso file. */ + if (re->loop_by == file) + return (-1); + re->loop_by = file; re = re->parent; + } if (re == NULL) return (-1); diff --git a/lib/libarchive/archive_string.c b/lib/libarchive/archive_string.c index d68ad58..c67182d 100644 --- a/lib/libarchive/archive_string.c +++ b/lib/libarchive/archive_string.c @@ -152,7 +152,7 @@ __archive_strncat(struct archive_string *as, const void *_p, size_t n) /* Like strlen(p), except won't examine positions beyond p[n]. */ s = 0; pp = p; - while (*pp && s < n) { + while (s < n && *pp) { pp++; s++; } diff --git a/lib/libarchive/archive_util.c b/lib/libarchive/archive_util.c index 4c0de02..8f2b4c6 100644 --- a/lib/libarchive/archive_util.c +++ b/lib/libarchive/archive_util.c @@ -155,6 +155,7 @@ archive_clear_error(struct archive *a) { archive_string_empty(&a->error_string); a->error = NULL; + a->archive_error_number = 0; } void diff --git a/lib/libarchive/archive_write_disk.c b/lib/libarchive/archive_write_disk.c index 2319220..49ced58 100644 --- a/lib/libarchive/archive_write_disk.c +++ b/lib/libarchive/archive_write_disk.c @@ -1513,6 +1513,22 @@ check_symlinks(struct archive_write_disk *a) } #if defined(_WIN32) || defined(__CYGWIN__) +static int +guidword(const char *p, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if ((*p >= '0' && *p <= '9') || + (*p >= 'a' && *p <= 'f') || + (*p >= 'A' && *p <= 'F')) + p++; + else + return (-1); + } + return (0); +} + /* * 1. Convert a path separator from '\' to '/' . * We shouldn't check multi-byte character directly because some @@ -1521,26 +1537,92 @@ check_symlinks(struct archive_write_disk *a) * 2. Replace unusable characters in Windows with underscore('_'). * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx */ -static void +static int cleanup_pathname_win(struct archive_write_disk *a) { wchar_t wc; char *p; size_t alen, l; - alen = 0; - l = 0; - for (p = a->name; *p != '\0'; p++) { - ++alen; - if (*p == '\\') - l = 1; + p = a->name; + /* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or + * "\\?\Volume{GUID}\" + * (absolute path prefixes used by Windows API) */ + if ((p[0] == '\\' || p[0] == '/') && (p[1] == '\\' || p[1] == '/' ) && + (p[2] == '.' || p[2] == '?') && (p[3] == '\\' || p[3] == '/')) + { + /* A path begin with "\\?\UNC\" */ + if (p[2] == '?' && + (p[4] == 'U' || p[4] == 'u') && + (p[5] == 'N' || p[5] == 'n') && + (p[6] == 'C' || p[6] == 'c') && + (p[7] == '\\' || p[7] == '/')) + p += 8; + /* A path begin with "\\?\Volume{GUID}\" */ + else if (p[2] == '?' && + (p[4] == 'V' || p[4] == 'v') && + (p[5] == 'O' || p[5] == 'o') && + (p[6] == 'L' || p[6] == 'l') && + (p[7] == 'U' || p[7] == 'u') && + (p[8] == 'M' || p[8] == 'm') && + (p[9] == 'E' || p[9] == 'e') && + p[10] == '{') { + if (guidword(p+11, 8) == 0 && p[19] == '-' && + guidword(p+20, 4) == 0 && p[24] == '-' && + guidword(p+25, 4) == 0 && p[29] == '-' && + guidword(p+30, 4) == 0 && p[34] == '-' && + guidword(p+35, 12) == 0 && p[47] == '}' && + (p[48] == '\\' || p[48] == '/')) + p += 49; + else + p += 4; + /* A path begin with "\\.\PhysicalDriveX" */ + } else if (p[2] == '.' && + (p[4] == 'P' || p[4] == 'p') && + (p[5] == 'H' || p[5] == 'h') && + (p[6] == 'Y' || p[6] == 'y') && + (p[7] == 'S' || p[7] == 's') && + (p[8] == 'I' || p[8] == 'i') && + (p[9] == 'C' || p[9] == 'c') && + (p[9] == 'A' || p[9] == 'a') && + (p[9] == 'L' || p[9] == 'l') && + (p[9] == 'D' || p[9] == 'd') && + (p[9] == 'R' || p[9] == 'r') && + (p[9] == 'I' || p[9] == 'i') && + (p[9] == 'V' || p[9] == 'v') && + (p[9] == 'E' || p[9] == 'e') && + (p[10] >= '0' && p[10] <= '9') && + p[11] == '\0') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Path is a physical drive name"); + return (ARCHIVE_FAILED); + } else + p += 4; + } + + /* Skip leading drive letter from archives created + * on Windows. */ + if (((p[0] >= 'a' && p[0] <= 'z') || + (p[0] >= 'A' && p[0] <= 'Z')) && + p[1] == ':') { + if (p[2] == '\0') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Path is a drive name"); + return (ARCHIVE_FAILED); + } + if (p[2] == '\\' || p[2] == '/') + p += 3; + } + + for (; *p != '\0'; p++) { /* Rewrite the path name if its character is a unusable. */ if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || *p == '<' || *p == '>' || *p == '|') *p = '_'; } - if (alen == 0 || l == 0) - return; + alen = p - a->name; + if (alen == 0 || strchr(a->name, '\\') == NULL) + return (ARCHIVE_OK); /* * Convert path separator. */ @@ -1560,6 +1642,7 @@ cleanup_pathname_win(struct archive_write_disk *a) p += l; alen -= l; } + return (ARCHIVE_OK); } #endif @@ -1583,7 +1666,8 @@ cleanup_pathname(struct archive_write_disk *a) } #if defined(_WIN32) || defined(__CYGWIN__) - cleanup_pathname_win(a); + if (cleanup_pathname_win(a) != ARCHIVE_OK) + return (ARCHIVE_FAILED); #endif /* Skip leading '/'. */ if (*src == '/') -- cgit v1.1