Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/unzip/unzip.c
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
#include <stdarg.h> | #include <stdarg.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <archive.h> | #include <archive.h> | ||||
#include <archive_entry.h> | #include <archive_entry.h> | ||||
#include <readpassphrase.h> | |||||
/* command-line options */ | /* command-line options */ | ||||
static int a_opt; /* convert EOL */ | static int a_opt; /* convert EOL */ | ||||
static int C_opt; /* match case-insensitively */ | static int C_opt; /* match case-insensitively */ | ||||
static int c_opt; /* extract to stdout */ | static int c_opt; /* extract to stdout */ | ||||
static const char *d_arg; /* directory */ | static const char *d_arg; /* directory */ | ||||
static int f_opt; /* update existing files only */ | static int f_opt; /* update existing files only */ | ||||
static int j_opt; /* junk directories */ | static int j_opt; /* junk directories */ | ||||
static int L_opt; /* lowercase names */ | static int L_opt; /* lowercase names */ | ||||
static int n_opt; /* never overwrite */ | static int n_opt; /* never overwrite */ | ||||
static int o_opt; /* always overwrite */ | static int o_opt; /* always overwrite */ | ||||
static int p_opt; /* extract to stdout, quiet */ | static int p_opt; /* extract to stdout, quiet */ | ||||
static char *P_arg; /* passphrase */ | |||||
static int q_opt; /* quiet */ | static int q_opt; /* quiet */ | ||||
static int t_opt; /* test */ | static int t_opt; /* test */ | ||||
static int u_opt; /* update */ | static int u_opt; /* update */ | ||||
static int v_opt; /* verbose/list */ | static int v_opt; /* verbose/list */ | ||||
static const char *y_str = ""; /* 4 digit year */ | static const char *y_str = ""; /* 4 digit year */ | ||||
static int Z1_opt; /* zipinfo mode list files only */ | static int Z1_opt; /* zipinfo mode list files only */ | ||||
/* debug flag */ | /* debug flag */ | ||||
Show All 16 Lines | |||||
/* | /* | ||||
* Indicates that last info() did not end with EOL. This helps error() et | * Indicates that last info() did not end with EOL. This helps error() et | ||||
* al. avoid printing an error message on the same line as an incomplete | * al. avoid printing an error message on the same line as an incomplete | ||||
* informational message. | * informational message. | ||||
*/ | */ | ||||
static int noeol; | static int noeol; | ||||
/* for an interactive passphrase input */ | |||||
static char *passphrase_buf; | |||||
/* fatal error message + errno */ | /* fatal error message + errno */ | ||||
static void | static void | ||||
error(const char *fmt, ...) | error(const char *fmt, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
if (noeol) | if (noeol) | ||||
fprintf(stdout, "\n"); | fprintf(stdout, "\n"); | ||||
fflush(stdout); | fflush(stdout); | ||||
fprintf(stderr, "unzip: "); | fprintf(stderr, "unzip: "); | ||||
va_start(ap, fmt); | va_start(ap, fmt); | ||||
vfprintf(stderr, fmt, ap); | vfprintf(stderr, fmt, ap); | ||||
va_end(ap); | va_end(ap); | ||||
fprintf(stderr, ": %s\n", strerror(errno)); | fprintf(stderr, ": %s\n", strerror(errno)); | ||||
exit(1); | exit(EXIT_FAILURE); | ||||
} | } | ||||
/* fatal error message, no errno */ | /* fatal error message, no errno */ | ||||
static void | static void | ||||
errorx(const char *fmt, ...) | errorx(const char *fmt, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
if (noeol) | if (noeol) | ||||
fprintf(stdout, "\n"); | fprintf(stdout, "\n"); | ||||
fflush(stdout); | fflush(stdout); | ||||
fprintf(stderr, "unzip: "); | fprintf(stderr, "unzip: "); | ||||
va_start(ap, fmt); | va_start(ap, fmt); | ||||
vfprintf(stderr, fmt, ap); | vfprintf(stderr, fmt, ap); | ||||
va_end(ap); | va_end(ap); | ||||
fprintf(stderr, "\n"); | fprintf(stderr, "\n"); | ||||
exit(1); | exit(EXIT_FAILURE); | ||||
} | } | ||||
/* non-fatal error message + errno */ | /* non-fatal error message + errno */ | ||||
static void | static void | ||||
warning(const char *fmt, ...) | warning(const char *fmt, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
▲ Show 20 Lines • Show All 712 Lines • ▼ Show 20 Lines | test(struct archive *a, struct archive_entry *e) | ||||
/* shouldn't be necessary, but it doesn't hurt */ | /* shouldn't be necessary, but it doesn't hurt */ | ||||
ac(archive_read_data_skip(a)); | ac(archive_read_data_skip(a)); | ||||
return error_count; | return error_count; | ||||
} | } | ||||
/* | /* | ||||
* Callback function for reading passphrase. | |||||
* Originally from cpio.c and passphrase.c, libarchive. | |||||
*/ | |||||
#define PPBUFF_SIZE 1024 | |||||
static const char * | |||||
passphrase_callback(struct archive *a, void *_client_data) | |||||
{ | |||||
char *p; | |||||
(void)a; /* UNUSED */ | |||||
(void)_client_data; /* UNUSED */ | |||||
if (passphrase_buf == NULL) { | |||||
passphrase_buf = malloc(PPBUFF_SIZE); | |||||
if (passphrase_buf == NULL) { | |||||
errno = ENOMEM; | |||||
error("malloc()"); | |||||
} | |||||
} | |||||
p = readpassphrase("\nEnter password: ", passphrase_buf, | |||||
PPBUFF_SIZE, RPP_ECHO_OFF); | |||||
if (p == NULL && errno != EINTR) | |||||
error("Error reading password"); | |||||
return p; | |||||
} | |||||
/* | |||||
* Main loop: open the zipfile, iterate over its contents and decide what | * Main loop: open the zipfile, iterate over its contents and decide what | ||||
* to do with each entry. | * to do with each entry. | ||||
*/ | */ | ||||
static void | static void | ||||
unzip(const char *fn) | unzip(const char *fn) | ||||
{ | { | ||||
struct archive *a; | struct archive *a; | ||||
struct archive_entry *e; | struct archive_entry *e; | ||||
int ret; | int ret; | ||||
uintmax_t total_size, file_count, error_count; | uintmax_t total_size, file_count, error_count; | ||||
if ((a = archive_read_new()) == NULL) | if ((a = archive_read_new()) == NULL) | ||||
error("archive_read_new failed"); | error("archive_read_new failed"); | ||||
ac(archive_read_support_format_zip(a)); | ac(archive_read_support_format_zip(a)); | ||||
if (P_arg) | |||||
archive_read_add_passphrase(a, P_arg); | |||||
else | |||||
archive_read_set_passphrase_callback(a, passphrase_buf, | |||||
ak: We use global passphrase_buf pointer, so we can set *_client_data here to NULL… | |||||
nyanAuthorUnsubmitted Done Inline ActionsThank you. I'll fix. nyan: Thank you. I'll fix. | |||||
&passphrase_callback); | |||||
ac(archive_read_open_filename(a, fn, 8192)); | ac(archive_read_open_filename(a, fn, 8192)); | ||||
if (!zipinfo_mode) { | if (!zipinfo_mode) { | ||||
if (!p_opt && !q_opt) | if (!p_opt && !q_opt) | ||||
printf("Archive: %s\n", fn); | printf("Archive: %s\n", fn); | ||||
if (v_opt == 1) { | if (v_opt == 1) { | ||||
printf(" Length %sDate Time Name\n", y_str); | printf(" Length %sDate Time Name\n", y_str); | ||||
printf(" -------- %s---- ---- ----\n", y_str); | printf(" -------- %s---- ---- ----\n", y_str); | ||||
Show All 39 Lines | if (v_opt == 1) { | ||||
printf("%8ju %7ju 0%% %s%ju file%s\n", | printf("%8ju %7ju 0%% %s%ju file%s\n", | ||||
total_size, total_size, y_str, file_count, | total_size, total_size, y_str, file_count, | ||||
file_count != 1 ? "s" : ""); | file_count != 1 ? "s" : ""); | ||||
} | } | ||||
} | } | ||||
ac(archive_read_free(a)); | ac(archive_read_free(a)); | ||||
if (passphrase_buf != NULL) { | |||||
memset_s(passphrase_buf, PPBUFF_SIZE, 0, PPBUFF_SIZE); | |||||
free(passphrase_buf); | |||||
} | |||||
if (t_opt) { | if (t_opt) { | ||||
if (error_count > 0) { | if (error_count > 0) { | ||||
errorx("%ju checksum error(s) found.", error_count); | errorx("%ju checksum error(s) found.", error_count); | ||||
} | } | ||||
else { | else { | ||||
printf("No errors detected in compressed data of %s.\n", | printf("No errors detected in compressed data of %s.\n", | ||||
fn); | fn); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
fprintf(stderr, "Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] [-x pattern] " | fprintf(stderr, "Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] " | ||||
"zipfile\n"); | "[-x pattern] [-P password] zipfile\n"); | ||||
exit(1); | exit(EXIT_FAILURE); | ||||
} | } | ||||
static int | static int | ||||
getopts(int argc, char *argv[]) | getopts(int argc, char *argv[]) | ||||
{ | { | ||||
int opt; | int opt; | ||||
optreset = optind = 1; | optreset = optind = 1; | ||||
while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:yZ1")) != -1) | while ((opt = getopt(argc, argv, "aCcd:fjLlnopP:qtuvx:yZ1")) != -1) | ||||
switch (opt) { | switch (opt) { | ||||
case '1': | case '1': | ||||
Z1_opt = 1; | Z1_opt = 1; | ||||
break; | break; | ||||
case 'a': | case 'a': | ||||
a_opt = 1; | a_opt = 1; | ||||
break; | break; | ||||
case 'C': | case 'C': | ||||
Show All 23 Lines | case 'n': | ||||
break; | break; | ||||
case 'o': | case 'o': | ||||
o_opt = 1; | o_opt = 1; | ||||
q_opt = 1; | q_opt = 1; | ||||
break; | break; | ||||
case 'p': | case 'p': | ||||
p_opt = 1; | p_opt = 1; | ||||
break; | break; | ||||
case 'P': | |||||
P_arg = optarg; | |||||
break; | |||||
case 'q': | case 'q': | ||||
q_opt = 1; | q_opt = 1; | ||||
break; | break; | ||||
case 't': | case 't': | ||||
t_opt = 1; | t_opt = 1; | ||||
break; | break; | ||||
case 'u': | case 'u': | ||||
u_opt = 1; | u_opt = 1; | ||||
Show All 40 Lines | main(int argc, char *argv[]) | ||||
nopts = getopts(argc, argv); | nopts = getopts(argc, argv); | ||||
/* | /* | ||||
* When more of the zipinfo mode options are implemented, this | * When more of the zipinfo mode options are implemented, this | ||||
* will need to change. | * will need to change. | ||||
*/ | */ | ||||
if (zipinfo_mode && !Z1_opt) { | if (zipinfo_mode && !Z1_opt) { | ||||
printf("Zipinfo mode needs additional options\n"); | printf("Zipinfo mode needs additional options\n"); | ||||
exit(1); | exit(EXIT_FAILURE); | ||||
} | } | ||||
if (argc <= nopts) | if (argc <= nopts) | ||||
usage(); | usage(); | ||||
zipfile = argv[nopts++]; | zipfile = argv[nopts++]; | ||||
if (strcmp(zipfile, "-") == 0) | if (strcmp(zipfile, "-") == 0) | ||||
zipfile = NULL; /* STDIN */ | zipfile = NULL; /* STDIN */ | ||||
while (nopts < argc && *argv[nopts] != '-') | while (nopts < argc && *argv[nopts] != '-') | ||||
add_pattern(&include, argv[nopts++]); | add_pattern(&include, argv[nopts++]); | ||||
nopts--; /* fake argv[0] */ | nopts--; /* fake argv[0] */ | ||||
nopts += getopts(argc - nopts, argv + nopts); | nopts += getopts(argc - nopts, argv + nopts); | ||||
if (n_opt + o_opt + u_opt > 1) | if (n_opt + o_opt + u_opt > 1) | ||||
errorx("-n, -o and -u are contradictory"); | errorx("-n, -o and -u are contradictory"); | ||||
unzip(zipfile); | unzip(zipfile); | ||||
exit(0); | exit(EXIT_SUCCESS); | ||||
} | } |
We use global passphrase_buf pointer, so we can set *_client_data here to NULL: archive_read_set_passphrase_callback(a, NULL, &passphrase_callback);