mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-01 02:03:31 +00:00
Implement the rename query, for when a file with the same name as the one
about to be extracted already exists. The question, and interpretation of the response is deliberately compatible with Info-Zip. This change was originally obtained from NetBSD, but has three changes: - better compatibility with Info-Zip in the handling of ^D - Use getdelim() rather than getline() - bug fix: != changed to == in the "file rename" code I suspect the latter is also a bug in NetBSD, but I can't easily confirm this. PR: bin/143307 Reviewed by: rdivacky (change to unzip.c only) Obtained from: NetBSD src/usr.bin/unzip/unzip.c 1.8 MFC after: 1 month
This commit is contained in:
parent
d01c5f360e
commit
cf4bd0f272
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=203977
@ -158,17 +158,6 @@ utility is only able to process ZIP archives handled by
|
|||||||
Depending on the installed version of
|
Depending on the installed version of
|
||||||
.Xr libarchive ,
|
.Xr libarchive ,
|
||||||
this may or may not include self-extracting archives.
|
this may or may not include self-extracting archives.
|
||||||
.Sh BUGS
|
|
||||||
The
|
|
||||||
.Nm
|
|
||||||
utility currently does not support asking the user whether to
|
|
||||||
overwrite or skip a file that already exists on disk.
|
|
||||||
To be on the safe side, it will fail if it encounters a file that
|
|
||||||
already exists and neither the
|
|
||||||
.Fl n
|
|
||||||
nor the
|
|
||||||
.Fl o
|
|
||||||
command line option was specified.
|
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr libarchive 3
|
.Xr libarchive 3
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
|
@ -411,17 +411,65 @@ extract_dir(struct archive *a, struct archive_entry *e, const char *path)
|
|||||||
static unsigned char buffer[8192];
|
static unsigned char buffer[8192];
|
||||||
static char spinner[] = { '|', '/', '-', '\\' };
|
static char spinner[] = { '|', '/', '-', '\\' };
|
||||||
|
|
||||||
|
static int
|
||||||
|
handle_existing_file(char **path)
|
||||||
|
{
|
||||||
|
size_t alen;
|
||||||
|
ssize_t len;
|
||||||
|
char buf[4];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
|
||||||
|
*path);
|
||||||
|
if (fgets(buf, sizeof(buf), stdin) == 0) {
|
||||||
|
clearerr(stdin);
|
||||||
|
printf("NULL\n(EOF or read error, "
|
||||||
|
"treating as \"[N]one\"...)\n");
|
||||||
|
n_opt = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
switch (*buf) {
|
||||||
|
case 'A':
|
||||||
|
o_opt = 1;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 'y':
|
||||||
|
case 'Y':
|
||||||
|
(void)unlink(*path);
|
||||||
|
return 1;
|
||||||
|
case 'N':
|
||||||
|
n_opt = 1;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 'n':
|
||||||
|
return -1;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
printf("New name: ");
|
||||||
|
fflush(stdout);
|
||||||
|
free(*path);
|
||||||
|
*path = NULL;
|
||||||
|
alen = 0;
|
||||||
|
len = getdelim(path, &alen, '\n', stdin);
|
||||||
|
if ((*path)[len - 1] == '\n')
|
||||||
|
(*path)[len - 1] = '\0';
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract a regular file.
|
* Extract a regular file.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
extract_file(struct archive *a, struct archive_entry *e, const char *path)
|
extract_file(struct archive *a, struct archive_entry *e, char **path)
|
||||||
{
|
{
|
||||||
int mode;
|
int mode;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
struct timeval tv[2];
|
struct timeval tv[2];
|
||||||
int cr, fd, text, warn;
|
int cr, fd, text, warn, check;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
unsigned char *p, *q, *end;
|
unsigned char *p, *q, *end;
|
||||||
|
|
||||||
@ -431,32 +479,36 @@ extract_file(struct archive *a, struct archive_entry *e, const char *path)
|
|||||||
mtime = archive_entry_mtime(e);
|
mtime = archive_entry_mtime(e);
|
||||||
|
|
||||||
/* look for existing file of same name */
|
/* look for existing file of same name */
|
||||||
if (lstat(path, &sb) == 0) {
|
recheck:
|
||||||
|
if (lstat(*path, &sb) == 0) {
|
||||||
if (u_opt || f_opt) {
|
if (u_opt || f_opt) {
|
||||||
/* check if up-to-date */
|
/* check if up-to-date */
|
||||||
if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime)
|
if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime)
|
||||||
return;
|
return;
|
||||||
(void)unlink(path);
|
(void)unlink(*path);
|
||||||
} else if (o_opt) {
|
} else if (o_opt) {
|
||||||
/* overwrite */
|
/* overwrite */
|
||||||
(void)unlink(path);
|
(void)unlink(*path);
|
||||||
} else if (n_opt) {
|
} else if (n_opt) {
|
||||||
/* do not overwrite */
|
/* do not overwrite */
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
/* XXX ask user */
|
check = handle_existing_file(path);
|
||||||
errorx("not implemented");
|
if (check == 0)
|
||||||
|
goto recheck;
|
||||||
|
if (check == -1)
|
||||||
|
return; /* do not overwrite */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (f_opt)
|
if (f_opt)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fd = open(path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
|
if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
|
||||||
error("open('%s')", path);
|
error("open('%s')", *path);
|
||||||
|
|
||||||
/* loop over file contents and write to disk */
|
/* loop over file contents and write to disk */
|
||||||
info(" extracting: %s", path);
|
info(" extracting: %s", *path);
|
||||||
text = a_opt;
|
text = a_opt;
|
||||||
warn = 0;
|
warn = 0;
|
||||||
cr = 0;
|
cr = 0;
|
||||||
@ -473,7 +525,7 @@ extract_file(struct archive *a, struct archive_entry *e, const char *path)
|
|||||||
if (a_opt && cr) {
|
if (a_opt && cr) {
|
||||||
if (len == 0 || buffer[0] != '\n')
|
if (len == 0 || buffer[0] != '\n')
|
||||||
if (write(fd, "\r", 1) != 1)
|
if (write(fd, "\r", 1) != 1)
|
||||||
error("write('%s')", path);
|
error("write('%s')", *path);
|
||||||
cr = 0;
|
cr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,7 +556,7 @@ extract_file(struct archive *a, struct archive_entry *e, const char *path)
|
|||||||
/* simple case */
|
/* simple case */
|
||||||
if (!a_opt || !text) {
|
if (!a_opt || !text) {
|
||||||
if (write(fd, buffer, len) != len)
|
if (write(fd, buffer, len) != len)
|
||||||
error("write('%s')", path);
|
error("write('%s')", *path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,7 +566,7 @@ extract_file(struct archive *a, struct archive_entry *e, const char *path)
|
|||||||
if (!warn && !isascii(*q)) {
|
if (!warn && !isascii(*q)) {
|
||||||
warningx("%s may be corrupted due"
|
warningx("%s may be corrupted due"
|
||||||
" to weak text file detection"
|
" to weak text file detection"
|
||||||
" heuristic", path);
|
" heuristic", *path);
|
||||||
warn = 1;
|
warn = 1;
|
||||||
}
|
}
|
||||||
if (q[0] != '\r')
|
if (q[0] != '\r')
|
||||||
@ -527,7 +579,7 @@ extract_file(struct archive *a, struct archive_entry *e, const char *path)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (write(fd, p, q - p) != q - p)
|
if (write(fd, p, q - p) != q - p)
|
||||||
error("write('%s')", path);
|
error("write('%s')", *path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tty)
|
if (tty)
|
||||||
@ -542,9 +594,9 @@ extract_file(struct archive *a, struct archive_entry *e, const char *path)
|
|||||||
tv[1].tv_sec = mtime;
|
tv[1].tv_sec = mtime;
|
||||||
tv[1].tv_usec = 0;
|
tv[1].tv_usec = 0;
|
||||||
if (futimes(fd, tv) != 0)
|
if (futimes(fd, tv) != 0)
|
||||||
error("utimes('%s')", path);
|
error("utimes('%s')", *path);
|
||||||
if (close(fd) != 0)
|
if (close(fd) != 0)
|
||||||
error("close('%s')", path);
|
error("close('%s')", *path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -620,7 +672,7 @@ extract(struct archive *a, struct archive_entry *e)
|
|||||||
if (S_ISDIR(filetype))
|
if (S_ISDIR(filetype))
|
||||||
extract_dir(a, e, realpathname);
|
extract_dir(a, e, realpathname);
|
||||||
else
|
else
|
||||||
extract_file(a, e, realpathname);
|
extract_file(a, e, &realpathname);
|
||||||
|
|
||||||
free(realpathname);
|
free(realpathname);
|
||||||
free(pathname);
|
free(pathname);
|
||||||
|
Loading…
Reference in New Issue
Block a user