unzip: fix Mac build.

Turns out the Mac doesn't have <error.h>. Add our own "die" function
instead, and use it everywhere so the Mac isn't using an untested
codepath.

One upside to this is that we'll now call ourselves "unzip" even when
run as `ziptool unzip ...`, which was awkward to fix with <error.h> but
trivial if we're rolling our own anyway.

Test: still works on Linux
Change-Id: I9cb1922595a21cd9f6d55a70d67e30090f8b7f21
This commit is contained in:
Elliott Hughes 2019-11-03 08:30:33 -08:00
parent 4645210097
commit bcd810622b

View file

@ -15,11 +15,11 @@
*/
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <getopt.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
@ -64,6 +64,20 @@ static uint64_t total_uncompressed_length = 0;
static uint64_t total_compressed_length = 0;
static size_t file_count = 0;
static const char* g_progname;
static void die(int error, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s: ", g_progname);
vfprintf(stderr, fmt, ap);
if (error != 0) fprintf(stderr, ": %s", strerror(error));
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
static bool ShouldInclude(const std::string& name) {
// Explicitly excluded?
if (!excludes.empty()) {
@ -155,7 +169,7 @@ static bool PromptOverwrite(const std::string& dst) {
char* line = nullptr;
size_t n;
if (getline(&line, &n, stdin) == -1) {
error(1, 0, "(EOF/read error; assuming [N]one...)");
die(0, "(EOF/read error; assuming [N]one...)");
overwrite_mode = kNever;
return false;
}
@ -183,10 +197,10 @@ static void ExtractToPipe(ZipArchiveHandle zah, ZipEntry& entry, const std::stri
uint8_t* buffer = new uint8_t[entry.uncompressed_length];
int err = ExtractToMemory(zah, &entry, buffer, entry.uncompressed_length);
if (err < 0) {
error(1, 0, "failed to extract %s: %s", name.c_str(), ErrorCodeString(err));
die(0, "failed to extract %s: %s", name.c_str(), ErrorCodeString(err));
}
if (!android::base::WriteFully(1, buffer, entry.uncompressed_length)) {
error(1, errno, "failed to write %s to stdout", name.c_str());
die(errno, "failed to write %s to stdout", name.c_str());
}
delete[] buffer;
}
@ -194,7 +208,7 @@ static void ExtractToPipe(ZipArchiveHandle zah, ZipEntry& entry, const std::stri
static void ExtractOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
// Bad filename?
if (StartsWith(name, "/") || StartsWith(name, "../") || name.find("/../") != std::string::npos) {
error(1, 0, "bad filename %s", name.c_str());
die(0, "bad filename %s", name.c_str());
}
// Where are we actually extracting to (for human-readable output)?
@ -207,7 +221,7 @@ static void ExtractOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string&
// Ensure the directory hierarchy exists.
if (!MakeDirectoryHierarchy(android::base::Dirname(name))) {
error(1, errno, "couldn't create directory hierarchy for %s", dst.c_str());
die(errno, "couldn't create directory hierarchy for %s", dst.c_str());
}
// An entry in a zip file can just be a directory itself.
@ -218,7 +232,7 @@ static void ExtractOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string&
struct stat sb;
if (stat(name.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) return;
}
error(1, errno, "couldn't extract directory %s", dst.c_str());
die(errno, "couldn't extract directory %s", dst.c_str());
}
return;
}
@ -231,12 +245,12 @@ static void ExtractOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string&
// Either overwrite_mode is kAlways or the user consented to this specific case.
fd = open(name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, entry.unix_mode);
}
if (fd == -1) error(1, errno, "couldn't create file %s", dst.c_str());
if (fd == -1) die(errno, "couldn't create file %s", dst.c_str());
// Actually extract into the file.
if (!flag_q) printf(" inflating: %s\n", dst.c_str());
int err = ExtractEntryToFile(zah, &entry, fd);
if (err < 0) error(1, 0, "failed to extract %s: %s", dst.c_str(), ErrorCodeString(err));
if (err < 0) die(0, "failed to extract %s: %s", dst.c_str(), ErrorCodeString(err));
close(fd);
}
@ -345,7 +359,7 @@ static void ProcessAll(ZipArchiveHandle zah) {
void* cookie;
int err = StartIteration(zah, &cookie);
if (err != 0) {
error(1, 0, "couldn't iterate %s: %s", archive_name, ErrorCodeString(err));
die(0, "couldn't iterate %s: %s", archive_name, ErrorCodeString(err));
}
ZipEntry entry;
@ -354,7 +368,7 @@ static void ProcessAll(ZipArchiveHandle zah) {
if (ShouldInclude(name)) ProcessOne(zah, entry, name);
}
if (err < -1) error(1, 0, "failed iterating %s: %s", archive_name, ErrorCodeString(err));
if (err < -1) die(0, "failed iterating %s: %s", archive_name, ErrorCodeString(err));
EndIteration(cookie);
MaybeShowFooter();
@ -420,14 +434,14 @@ static void HandleCommonOption(int opt) {
int main(int argc, char* argv[]) {
// Who am I, and what am I doing?
const char* base = basename(argv[0]);
if (!strcmp(base, "ziptool") && argc > 1) return main(argc - 1, argv + 1);
if (!strcmp(base, "unzip")) {
g_progname = basename(argv[0]);
if (!strcmp(g_progname, "ziptool") && argc > 1) return main(argc - 1, argv + 1);
if (!strcmp(g_progname, "unzip")) {
role = kUnzip;
} else if (!strcmp(base, "zipinfo")) {
} else if (!strcmp(g_progname, "zipinfo")) {
role = kZipinfo;
} else {
error(1, 0, "run as ziptool with unzip or zipinfo as the first argument, or symlink");
die(0, "run as ziptool with unzip or zipinfo as the first argument, or symlink");
}
static const struct option opts[] = {
@ -484,19 +498,19 @@ int main(int argc, char* argv[]) {
}
}
if (!archive_name) error(1, 0, "missing archive filename");
if (!archive_name) die(0, "missing archive filename");
// We can't support "-" to unzip from stdin because libziparchive relies on mmap.
ZipArchiveHandle zah;
int32_t err;
if ((err = OpenArchive(archive_name, &zah)) != 0) {
error(1, 0, "couldn't open %s: %s", archive_name, ErrorCodeString(err));
die(0, "couldn't open %s: %s", archive_name, ErrorCodeString(err));
}
// Implement -d by changing into that directory.
// We'll create implicit directories based on paths in the zip file, but we
// require that the -d directory already exists.
if (flag_d && chdir(flag_d) == -1) error(1, errno, "couldn't chdir to %s", flag_d);
if (flag_d && chdir(flag_d) == -1) die(errno, "couldn't chdir to %s", flag_d);
ProcessAll(zah);