Loading libziparchive/Android.bp +7 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,7 @@ cc_benchmark { } cc_binary { name: "unzip", name: "ziptool", defaults: ["libziparchive_flags"], srcs: ["unzip.cpp"], shared_libs: [ Loading @@ -183,6 +183,12 @@ cc_binary { "libziparchive", ], recovery_available: true, host_supported: true, target: { android: { symlinks: ["unzip", "zipinfo"], }, }, } cc_fuzz { Loading libziparchive/include/ziparchive/zip_archive.h +19 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,12 @@ struct ZipEntry { // The offset to the start of data for this ZipEntry. off64_t offset; // The version of zip and the host file system this came from. uint16_t version_made_by; // Whether this entry is believed to be text or binary. bool is_text; }; struct ZipArchive; Loading Loading @@ -125,6 +131,19 @@ int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* de */ void CloseArchive(ZipArchiveHandle archive); /** See GetArchiveInfo(). */ struct ZipArchiveInfo { /** The size in bytes of the archive itself. Used by zipinfo. */ off64_t archive_size; /** The number of entries in the archive. */ size_t entry_count; }; /** * Returns information about the given archive. */ ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive); /* * Find an entry in the Zip archive, by name. |data| must be non-null. * Loading libziparchive/unzip.cpp +194 −91 Original line number Diff line number Diff line Loading @@ -40,12 +40,15 @@ enum OverwriteMode { kPrompt, }; static bool is_unzip; static OverwriteMode overwrite_mode = kPrompt; static bool flag_1 = false; static const char* flag_d = nullptr; static bool flag_l = false; static bool flag_p = false; static bool flag_q = false; static bool flag_v = false; static bool flag_x = false; static const char* archive_name = nullptr; static std::set<std::string> includes; static std::set<std::string> excludes; Loading Loading @@ -88,7 +91,9 @@ static int CompressionRatio(int64_t uncompressed, int64_t compressed) { return static_cast<int>((100LL * (uncompressed - compressed)) / uncompressed); } static void MaybeShowHeader() { static void MaybeShowHeader(ZipArchiveHandle zah) { if (is_unzip) { // unzip has three formats. if (!flag_q) printf("Archive: %s\n", archive_name); if (flag_v) { printf( Loading @@ -99,9 +104,19 @@ static void MaybeShowHeader() { " Length Date Time Name\n" "--------- ---------- ----- ----\n"); } } else { // zipinfo. if (!flag_1 && includes.empty() && excludes.empty()) { ZipArchiveInfo info{GetArchiveInfo(zah)}; printf("Archive: %s\n", archive_name); printf("Zip file size: %" PRId64 " bytes, number of entries: %zu\n", info.archive_size, info.entry_count); } } } static void MaybeShowFooter() { if (is_unzip) { if (flag_v) { printf( "-------- ------- --- -------\n" Loading @@ -115,6 +130,13 @@ static void MaybeShowFooter() { "%9" PRId64 " %zu file%s\n", total_uncompressed_length, file_count, (file_count == 1) ? "" : "s"); } } else { if (!flag_1 && includes.empty() && excludes.empty()) { printf("%zu files, %" PRId64 " bytes uncompressed, %" PRId64 " bytes compressed: %3d%%\n", file_count, total_uncompressed_length, total_compressed_length, CompressionRatio(total_uncompressed_length, total_compressed_length)); } } } static bool PromptOverwrite(const std::string& dst) { Loading Loading @@ -226,7 +248,47 @@ static void ListOne(const ZipEntry& entry, const std::string& name) { } } static void InfoOne(const ZipEntry& entry, const std::string& name) { if (flag_1) { // "android-ndk-r19b/sources/android/NOTICE" printf("%s\n", name.c_str()); return; } int version = entry.version_made_by & 0xff; int os = (entry.version_made_by >> 8) & 0xff; // TODO: Support suid/sgid? Non-Unix host file system attributes? char mode[] = "??????????"; if (os == 3) { mode[0] = S_ISDIR(entry.unix_mode) ? 'd' : (S_ISREG(entry.unix_mode) ? '-' : '?'); mode[1] = entry.unix_mode & S_IRUSR ? 'r' : '-'; mode[2] = entry.unix_mode & S_IWUSR ? 'w' : '-'; mode[3] = entry.unix_mode & S_IXUSR ? 'x' : '-'; mode[4] = entry.unix_mode & S_IRGRP ? 'r' : '-'; mode[5] = entry.unix_mode & S_IWGRP ? 'w' : '-'; mode[6] = entry.unix_mode & S_IXGRP ? 'x' : '-'; mode[7] = entry.unix_mode & S_IROTH ? 'r' : '-'; mode[8] = entry.unix_mode & S_IWOTH ? 'w' : '-'; mode[9] = entry.unix_mode & S_IXOTH ? 'x' : '-'; } // TODO: zipinfo (unlike unzip) sometimes uses time zone? // TODO: this uses 4-digit years because we're not barbarians unless interoperability forces it. tm t = entry.GetModificationTime(); char time[32]; snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min); // "-rw-r--r-- 3.0 unx 577 t- defX 19-Feb-12 16:09 android-ndk-r19b/sources/android/NOTICE" printf("%s %2d.%d %s %8d %c%c %s %s %s\n", mode, version / 10, version % 10, os == 3 ? "unx" : "???", entry.uncompressed_length, entry.is_text ? 't' : 'b', entry.has_data_descriptor ? 'X' : 'x', entry.method == kCompressStored ? "stor" : "defX", time, name.c_str()); } static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) { if (is_unzip) { if (flag_l || flag_v) { // -l or -lv or -lq or -v. ListOne(entry, name); Loading @@ -238,13 +300,17 @@ static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& ExtractOne(zah, entry, name); } } } else { // zipinfo or zipinfo -1. InfoOne(entry, name); } total_uncompressed_length += entry.uncompressed_length; total_compressed_length += entry.compressed_length; ++file_count; } static void ProcessAll(ZipArchiveHandle zah) { MaybeShowHeader(); MaybeShowHeader(zah); // libziparchive iteration order doesn't match the central directory. // We could sort, but that would cost extra and wouldn't match either. Loading @@ -267,6 +333,7 @@ static void ProcessAll(ZipArchiveHandle zah) { } static void ShowHelp(bool full) { if (is_unzip) { fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n"); if (!full) exit(EXIT_FAILURE); Loading @@ -283,23 +350,59 @@ static void ShowHelp(bool full) { "-q Quiet\n" "-v List contents verbosely\n" "-x FILE Exclude files\n"); } else { fprintf(full ? stdout : stderr, "usage: zipinfo [-1] ZIP [FILE...] [-x FILE...]\n"); if (!full) exit(EXIT_FAILURE); printf( "\n" "Show information about FILEs from ZIP archive. Default is all files.\n" "Both the include and exclude (-x) lists use shell glob patterns.\n" "\n" "-1 Show filenames only, one per line\n" "-x FILE Exclude files\n"); } exit(EXIT_SUCCESS); } static void HandleCommonOption(int opt) { switch (opt) { case 'h': ShowHelp(true); break; case 'x': flag_x = true; break; case 1: // -x swallows all following arguments, so we use '-' in the getopt // string and collect files here. if (!archive_name) { archive_name = optarg; } else if (flag_x) { excludes.insert(optarg); } else { includes.insert(optarg); } break; default: ShowHelp(false); break; } } int main(int argc, char* argv[]) { static struct option opts[] = { {"help", no_argument, 0, 'h'}, }; bool saw_x = false; is_unzip = !strcmp(basename(argv[0]), "unzip"); if (is_unzip) { int opt; while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) { switch (opt) { case 'd': flag_d = optarg; break; case 'h': ShowHelp(true); break; case 'l': flag_l = true; break; Loading @@ -318,22 +421,22 @@ int main(int argc, char* argv[]) { case 'v': flag_v = true; break; case 'x': saw_x = true; default: HandleCommonOption(opt); break; case 1: // -x swallows all following arguments, so we use '-' in the getopt // string and collect files here. if (!archive_name) { archive_name = optarg; } else if (saw_x) { excludes.insert(optarg); } else { includes.insert(optarg); } } } else { int opt; while ((opt = getopt_long(argc, argv, "-1hx", opts, nullptr)) != -1) { switch (opt) { case '1': flag_1 = true; break; default: ShowHelp(false); HandleCommonOption(opt); break; } } } Loading libziparchive/zip_archive.cc +13 −1 Original line number Diff line number Diff line Loading @@ -478,6 +478,13 @@ int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* de return OpenArchiveInternal(archive, debug_file_name); } ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive) { ZipArchiveInfo result; result.archive_size = archive->mapped_zip.GetFileLength(); result.entry_count = archive->num_entries; return result; } /* * Close a ZipArchive, closing the file and freeing the contents. */ Loading Loading @@ -614,12 +621,17 @@ static int32_t FindEntry(const ZipArchive* archive, const int32_t ent, ZipEntry* } // 4.4.2.1: the upper byte of `version_made_by` gives the source OS. Unix is 3. if ((cdr->version_made_by >> 8) == 3) { data->version_made_by = cdr->version_made_by; if ((data->version_made_by >> 8) == 3) { data->unix_mode = (cdr->external_file_attributes >> 16) & 0xffff; } else { data->unix_mode = 0777; } // 4.4.14: the lowest bit of the internal file attributes field indicates text. // Currently only needed to implement zipinfo. data->is_text = (cdr->internal_file_attributes & 1); // Check that the local file header name matches the declared // name in the central directory. if (lfh->file_name_length != nameLen) { Loading shell_and_utilities/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ phony { "tcpdump", "toolbox", "toybox", "unzip", "ziptool", ], } Loading Loading
libziparchive/Android.bp +7 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,7 @@ cc_benchmark { } cc_binary { name: "unzip", name: "ziptool", defaults: ["libziparchive_flags"], srcs: ["unzip.cpp"], shared_libs: [ Loading @@ -183,6 +183,12 @@ cc_binary { "libziparchive", ], recovery_available: true, host_supported: true, target: { android: { symlinks: ["unzip", "zipinfo"], }, }, } cc_fuzz { Loading
libziparchive/include/ziparchive/zip_archive.h +19 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,12 @@ struct ZipEntry { // The offset to the start of data for this ZipEntry. off64_t offset; // The version of zip and the host file system this came from. uint16_t version_made_by; // Whether this entry is believed to be text or binary. bool is_text; }; struct ZipArchive; Loading Loading @@ -125,6 +131,19 @@ int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* de */ void CloseArchive(ZipArchiveHandle archive); /** See GetArchiveInfo(). */ struct ZipArchiveInfo { /** The size in bytes of the archive itself. Used by zipinfo. */ off64_t archive_size; /** The number of entries in the archive. */ size_t entry_count; }; /** * Returns information about the given archive. */ ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive); /* * Find an entry in the Zip archive, by name. |data| must be non-null. * Loading
libziparchive/unzip.cpp +194 −91 Original line number Diff line number Diff line Loading @@ -40,12 +40,15 @@ enum OverwriteMode { kPrompt, }; static bool is_unzip; static OverwriteMode overwrite_mode = kPrompt; static bool flag_1 = false; static const char* flag_d = nullptr; static bool flag_l = false; static bool flag_p = false; static bool flag_q = false; static bool flag_v = false; static bool flag_x = false; static const char* archive_name = nullptr; static std::set<std::string> includes; static std::set<std::string> excludes; Loading Loading @@ -88,7 +91,9 @@ static int CompressionRatio(int64_t uncompressed, int64_t compressed) { return static_cast<int>((100LL * (uncompressed - compressed)) / uncompressed); } static void MaybeShowHeader() { static void MaybeShowHeader(ZipArchiveHandle zah) { if (is_unzip) { // unzip has three formats. if (!flag_q) printf("Archive: %s\n", archive_name); if (flag_v) { printf( Loading @@ -99,9 +104,19 @@ static void MaybeShowHeader() { " Length Date Time Name\n" "--------- ---------- ----- ----\n"); } } else { // zipinfo. if (!flag_1 && includes.empty() && excludes.empty()) { ZipArchiveInfo info{GetArchiveInfo(zah)}; printf("Archive: %s\n", archive_name); printf("Zip file size: %" PRId64 " bytes, number of entries: %zu\n", info.archive_size, info.entry_count); } } } static void MaybeShowFooter() { if (is_unzip) { if (flag_v) { printf( "-------- ------- --- -------\n" Loading @@ -115,6 +130,13 @@ static void MaybeShowFooter() { "%9" PRId64 " %zu file%s\n", total_uncompressed_length, file_count, (file_count == 1) ? "" : "s"); } } else { if (!flag_1 && includes.empty() && excludes.empty()) { printf("%zu files, %" PRId64 " bytes uncompressed, %" PRId64 " bytes compressed: %3d%%\n", file_count, total_uncompressed_length, total_compressed_length, CompressionRatio(total_uncompressed_length, total_compressed_length)); } } } static bool PromptOverwrite(const std::string& dst) { Loading Loading @@ -226,7 +248,47 @@ static void ListOne(const ZipEntry& entry, const std::string& name) { } } static void InfoOne(const ZipEntry& entry, const std::string& name) { if (flag_1) { // "android-ndk-r19b/sources/android/NOTICE" printf("%s\n", name.c_str()); return; } int version = entry.version_made_by & 0xff; int os = (entry.version_made_by >> 8) & 0xff; // TODO: Support suid/sgid? Non-Unix host file system attributes? char mode[] = "??????????"; if (os == 3) { mode[0] = S_ISDIR(entry.unix_mode) ? 'd' : (S_ISREG(entry.unix_mode) ? '-' : '?'); mode[1] = entry.unix_mode & S_IRUSR ? 'r' : '-'; mode[2] = entry.unix_mode & S_IWUSR ? 'w' : '-'; mode[3] = entry.unix_mode & S_IXUSR ? 'x' : '-'; mode[4] = entry.unix_mode & S_IRGRP ? 'r' : '-'; mode[5] = entry.unix_mode & S_IWGRP ? 'w' : '-'; mode[6] = entry.unix_mode & S_IXGRP ? 'x' : '-'; mode[7] = entry.unix_mode & S_IROTH ? 'r' : '-'; mode[8] = entry.unix_mode & S_IWOTH ? 'w' : '-'; mode[9] = entry.unix_mode & S_IXOTH ? 'x' : '-'; } // TODO: zipinfo (unlike unzip) sometimes uses time zone? // TODO: this uses 4-digit years because we're not barbarians unless interoperability forces it. tm t = entry.GetModificationTime(); char time[32]; snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min); // "-rw-r--r-- 3.0 unx 577 t- defX 19-Feb-12 16:09 android-ndk-r19b/sources/android/NOTICE" printf("%s %2d.%d %s %8d %c%c %s %s %s\n", mode, version / 10, version % 10, os == 3 ? "unx" : "???", entry.uncompressed_length, entry.is_text ? 't' : 'b', entry.has_data_descriptor ? 'X' : 'x', entry.method == kCompressStored ? "stor" : "defX", time, name.c_str()); } static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) { if (is_unzip) { if (flag_l || flag_v) { // -l or -lv or -lq or -v. ListOne(entry, name); Loading @@ -238,13 +300,17 @@ static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& ExtractOne(zah, entry, name); } } } else { // zipinfo or zipinfo -1. InfoOne(entry, name); } total_uncompressed_length += entry.uncompressed_length; total_compressed_length += entry.compressed_length; ++file_count; } static void ProcessAll(ZipArchiveHandle zah) { MaybeShowHeader(); MaybeShowHeader(zah); // libziparchive iteration order doesn't match the central directory. // We could sort, but that would cost extra and wouldn't match either. Loading @@ -267,6 +333,7 @@ static void ProcessAll(ZipArchiveHandle zah) { } static void ShowHelp(bool full) { if (is_unzip) { fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n"); if (!full) exit(EXIT_FAILURE); Loading @@ -283,23 +350,59 @@ static void ShowHelp(bool full) { "-q Quiet\n" "-v List contents verbosely\n" "-x FILE Exclude files\n"); } else { fprintf(full ? stdout : stderr, "usage: zipinfo [-1] ZIP [FILE...] [-x FILE...]\n"); if (!full) exit(EXIT_FAILURE); printf( "\n" "Show information about FILEs from ZIP archive. Default is all files.\n" "Both the include and exclude (-x) lists use shell glob patterns.\n" "\n" "-1 Show filenames only, one per line\n" "-x FILE Exclude files\n"); } exit(EXIT_SUCCESS); } static void HandleCommonOption(int opt) { switch (opt) { case 'h': ShowHelp(true); break; case 'x': flag_x = true; break; case 1: // -x swallows all following arguments, so we use '-' in the getopt // string and collect files here. if (!archive_name) { archive_name = optarg; } else if (flag_x) { excludes.insert(optarg); } else { includes.insert(optarg); } break; default: ShowHelp(false); break; } } int main(int argc, char* argv[]) { static struct option opts[] = { {"help", no_argument, 0, 'h'}, }; bool saw_x = false; is_unzip = !strcmp(basename(argv[0]), "unzip"); if (is_unzip) { int opt; while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) { switch (opt) { case 'd': flag_d = optarg; break; case 'h': ShowHelp(true); break; case 'l': flag_l = true; break; Loading @@ -318,22 +421,22 @@ int main(int argc, char* argv[]) { case 'v': flag_v = true; break; case 'x': saw_x = true; default: HandleCommonOption(opt); break; case 1: // -x swallows all following arguments, so we use '-' in the getopt // string and collect files here. if (!archive_name) { archive_name = optarg; } else if (saw_x) { excludes.insert(optarg); } else { includes.insert(optarg); } } } else { int opt; while ((opt = getopt_long(argc, argv, "-1hx", opts, nullptr)) != -1) { switch (opt) { case '1': flag_1 = true; break; default: ShowHelp(false); HandleCommonOption(opt); break; } } } Loading
libziparchive/zip_archive.cc +13 −1 Original line number Diff line number Diff line Loading @@ -478,6 +478,13 @@ int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* de return OpenArchiveInternal(archive, debug_file_name); } ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive) { ZipArchiveInfo result; result.archive_size = archive->mapped_zip.GetFileLength(); result.entry_count = archive->num_entries; return result; } /* * Close a ZipArchive, closing the file and freeing the contents. */ Loading Loading @@ -614,12 +621,17 @@ static int32_t FindEntry(const ZipArchive* archive, const int32_t ent, ZipEntry* } // 4.4.2.1: the upper byte of `version_made_by` gives the source OS. Unix is 3. if ((cdr->version_made_by >> 8) == 3) { data->version_made_by = cdr->version_made_by; if ((data->version_made_by >> 8) == 3) { data->unix_mode = (cdr->external_file_attributes >> 16) & 0xffff; } else { data->unix_mode = 0777; } // 4.4.14: the lowest bit of the internal file attributes field indicates text. // Currently only needed to implement zipinfo. data->is_text = (cdr->internal_file_attributes & 1); // Check that the local file header name matches the declared // name in the central directory. if (lfh->file_name_length != nameLen) { Loading
shell_and_utilities/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ phony { "tcpdump", "toolbox", "toybox", "unzip", "ziptool", ], } Loading