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:
parent
4645210097
commit
bcd810622b
1 changed files with 33 additions and 19 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue