version 1.65, 2005/07/22 08:38:46 |
version 1.66, 2006/03/13 14:49:59 |
|
|
{ |
{ |
FTS *ftsp; |
FTS *ftsp; |
FTSENT *entry; |
FTSENT *entry; |
struct stat osb; |
|
const struct compressor *method; |
const struct compressor *method; |
const char *s; |
const char *s; |
char *p, *infile; |
char *p, *infile; |
char outfile[MAXPATHLEN], _infile[MAXPATHLEN], suffix[16]; |
char outfile[MAXPATHLEN], _infile[MAXPATHLEN], suffix[16]; |
char *nargv[512]; /* some estimate based on ARG_MAX */ |
char *nargv[512]; /* some estimate based on ARG_MAX */ |
int bits, exists, oreg, ch, error, i, rc, oflag; |
int bits, ch, error, i, rc, cflag, oflag; |
|
|
oreg = exists = bits = oflag = 0; |
bits = cflag = oflag = 0; |
nosave = -1; |
nosave = -1; |
p = __progname; |
p = __progname; |
if (p[0] == 'g') { |
if (p[0] == 'g') { |
|
|
decomp = 0; |
decomp = 0; |
if (!strcmp(p, "zcat")) { |
if (!strcmp(p, "zcat")) { |
decomp++; |
decomp++; |
cat = 1; |
cflag = 1; |
} else { |
} else { |
if (p[0] == 'u' && p[1] == 'n') { |
if (p[0] == 'u' && p[1] == 'n') { |
p += 2; |
p += 2; |
|
|
errx(1, "illegal bit count -- %s", optarg); |
errx(1, "illegal bit count -- %s", optarg); |
break; |
break; |
case 'c': |
case 'c': |
cat = 1; |
cflag = 1; |
break; |
break; |
case 'd': /* Backward compatible. */ |
case 'd': /* Backward compatible. */ |
decomp++; |
decomp++; |
|
|
if (nargv[0] == NULL) |
if (nargv[0] == NULL) |
argv = nargv; |
argv = nargv; |
/* XXX - make sure we don't oflow nargv in $GZIP case (millert) */ |
/* XXX - make sure we don't oflow nargv in $GZIP case (millert) */ |
argv[0] = "/dev/stdin"; |
argv[0] = "-"; |
argv[1] = NULL; |
argv[1] = NULL; |
pipin++; |
|
if (!oflag) |
|
cat = 1; |
|
} else { |
|
for (i = 0; i < argc; i++) { |
|
if (argv[i][0] == '-' && argv[i][1] == '\0') { |
|
argv[i] = "/dev/stdin"; |
|
pipin++; |
|
cat = 1; |
|
} |
|
} |
|
} |
} |
if (oflag && (recurse || argc > 1)) |
if (oflag && (recurse || argc > 1)) |
errx(1, "-o option may only be used with a single input file"); |
errx(1, "-o option may only be used with a single input file"); |
|
|
if ((ftsp = fts_open(argv, FTS_PHYSICAL|FTS_NOCHDIR, 0)) == NULL) |
if ((ftsp = fts_open(argv, FTS_PHYSICAL|FTS_NOCHDIR, 0)) == NULL) |
err(1, NULL); |
err(1, NULL); |
for (rc = SUCCESS; (entry = fts_read(ftsp)) != NULL;) { |
for (rc = SUCCESS; (entry = fts_read(ftsp)) != NULL;) { |
|
cat = cflag; |
|
pipin = 0; |
infile = entry->fts_path; |
infile = entry->fts_path; |
switch (entry->fts_info) { |
switch (entry->fts_info) { |
case FTS_D: |
case FTS_D: |
|
|
* If file does not exist and has no suffix, |
* If file does not exist and has no suffix, |
* tack on the default suffix and try that. |
* tack on the default suffix and try that. |
*/ |
*/ |
/* XXX - is overwriting fts_statp legal? (millert) */ |
if (entry->fts_errno == ENOENT) { |
if (entry->fts_errno == ENOENT && |
if (infile[0] == '-' && infile[1] == '\0') { |
((p = strrchr(entry->fts_accpath, '.')) == NULL || |
infile = "stdin"; |
strcmp(p, suffix) != 0) && |
pipin++; |
snprintf(_infile, sizeof(_infile), "%s%s", infile, |
if (!oflag) |
suffix) < sizeof(_infile) && |
cat = 1; |
stat(_infile, entry->fts_statp) == 0 && |
break; |
S_ISREG(entry->fts_statp->st_mode)) { |
} |
infile = _infile; |
p = strrchr(entry->fts_accpath, '.'); |
break; |
if ((p == NULL || strcmp(p, suffix) != 0) && |
|
snprintf(_infile, sizeof(_infile), "%s%s", |
|
infile, suffix) < sizeof(_infile) && |
|
stat(_infile, entry->fts_statp) == 0 && |
|
S_ISREG(entry->fts_statp->st_mode)) { |
|
infile = _infile; |
|
break; |
|
} |
} |
} |
case FTS_ERR: |
case FTS_ERR: |
case FTS_DNR: |
case FTS_DNR: |
|
|
rc = rc ? rc : WARNING; |
rc = rc ? rc : WARNING; |
continue; |
continue; |
default: |
default: |
if (!S_ISREG(entry->fts_statp->st_mode) && !pipin && |
if (!S_ISREG(entry->fts_statp->st_mode) && |
!(S_ISLNK(entry->fts_statp->st_mode) && cat)) { |
!(S_ISLNK(entry->fts_statp->st_mode) && cat)) { |
warnx("%s not a regular file%s", |
warnx("%s not a regular file%s", |
infile, cat ? "" : ": unchanged"); |
infile, cat ? "" : ": unchanged"); |
|
|
continue; |
continue; |
} |
} |
|
|
if (cat) |
if (!oflag) { |
strlcpy(outfile, "/dev/stdout", sizeof outfile); |
if (cat) |
else if (!oflag) { |
strlcpy(outfile, "stdout", sizeof(outfile)); |
if (decomp) { |
else if (decomp) { |
if (set_outfile(infile, outfile, |
if (set_outfile(infile, outfile, |
sizeof outfile) == NULL) { |
sizeof outfile) == NULL) { |
if (!recurse) { |
if (!recurse) { |
|
|
} |
} |
} |
} |
|
|
if (!testmode) { |
|
exists = !stat(outfile, &osb); |
|
if (!force && exists && S_ISREG(osb.st_mode) && |
|
!permission(outfile)) { |
|
rc = rc ? rc : WARNING; |
|
continue; |
|
} |
|
oreg = !exists || S_ISREG(osb.st_mode); |
|
} |
|
|
|
if (verbose > 0 && !pipin && !list) |
if (verbose > 0 && !pipin && !list) |
fprintf(stderr, "%s:\t", infile); |
fprintf(stderr, "%s:\t", infile); |
|
|
|
|
break; |
break; |
default: |
default: |
rc = FAILURE; |
rc = FAILURE; |
if (oreg && unlink(outfile) && errno != ENOENT && |
|
verbose >= 0) { |
|
if (force) |
|
warn("output: %s", outfile); |
|
else |
|
err(1, "output: %s", outfile); |
|
} |
|
break; |
break; |
} |
} |
} |
} |
|
|
#ifndef SMALL |
#ifndef SMALL |
u_char buf[Z_BUFSIZE]; |
u_char buf[Z_BUFSIZE]; |
char *name; |
char *name; |
int error, ifd, ofd, flags; |
int error, ifd, ofd, flags, oreg; |
void *cookie; |
void *cookie; |
ssize_t nr; |
ssize_t nr; |
u_int32_t mtime; |
u_int32_t mtime; |
struct z_info info; |
struct z_info info; |
|
struct stat osb; |
|
|
mtime = 0; |
mtime = 0; |
flags = 0; |
flags = oreg = 0; |
error = SUCCESS; |
error = SUCCESS; |
name = NULL; |
name = NULL; |
cookie = NULL; |
cookie = NULL; |
|
|
if ((ifd = open(in, O_RDONLY)) < 0) { |
if (pipin) |
|
ifd = dup(STDIN_FILENO); |
|
else |
|
ifd = open(in, O_RDONLY); |
|
if (ifd < 0) { |
if (verbose >= 0) |
if (verbose >= 0) |
warn("%s", in); |
warn("%s", in); |
return (FAILURE); |
return (FAILURE); |
} |
} |
|
|
if ((ofd = open(out, O_WRONLY|O_CREAT, S_IWUSR)) < 0) { |
if (cat) |
|
ofd = dup(STDOUT_FILENO); |
|
else { |
|
if (stat(out, &osb) == 0) { |
|
oreg = S_ISREG(osb.st_mode); |
|
if (!force && oreg && !permission(out)) { |
|
(void) close(ifd); |
|
return (WARNING); |
|
} |
|
} |
|
ofd = open(out, O_WRONLY|O_CREAT, S_IWUSR); |
|
} |
|
if (ofd < 0) { |
if (verbose >= 0) |
if (verbose >= 0) |
warn("%s", out); |
warn("%s", out); |
(void) close(ifd); |
(void) close(ifd); |
|
|
} |
} |
if ((cookie = (*method->open)(ofd, "w", name, bits, mtime, flags)) == NULL) { |
if ((cookie = (*method->open)(ofd, "w", name, bits, mtime, flags)) == NULL) { |
if (verbose >= 0) |
if (verbose >= 0) |
warn("%s", in); |
warn("%s", out); |
|
if (oreg) |
|
(void) unlink(out); |
(void) close(ofd); |
(void) close(ofd); |
(void) close(ifd); |
(void) close(ifd); |
return (FAILURE); |
return (FAILURE); |
|
|
if (!force && info.total_out >= info.total_in) { |
if (!force && info.total_out >= info.total_in) { |
if (verbose > 0) |
if (verbose > 0) |
fprintf(stderr, "file would grow; left unmodified\n"); |
fprintf(stderr, "file would grow; left unmodified\n"); |
error = FAILURE; |
(void) unlink(out); |
|
error = WARNING; |
} |
} |
|
|
if (!error && verbose > 0) |
if (error) { |
|
if (oreg) |
|
(void) unlink(out); |
|
} else if (verbose > 0) |
verbose_info(out, info.total_out, info.total_in, info.hlen); |
verbose_info(out, info.total_out, info.total_in, info.hlen); |
|
|
return (error); |
return (error); |
|
|
int bits, struct stat *sb) |
int bits, struct stat *sb) |
{ |
{ |
u_char buf[Z_BUFSIZE]; |
u_char buf[Z_BUFSIZE]; |
int error, ifd, ofd; |
char oldname[MAXPATHLEN]; |
|
int error, oreg, ifd, ofd; |
void *cookie; |
void *cookie; |
ssize_t nr; |
ssize_t nr; |
struct z_info info; |
struct z_info info; |
|
struct stat osb; |
|
|
|
oreg = 0; |
error = SUCCESS; |
error = SUCCESS; |
cookie = NULL; |
cookie = NULL; |
|
|
if ((ifd = open(in, O_RDONLY)) < 0) { |
if (pipin) |
|
ifd = dup(STDIN_FILENO); |
|
else |
|
ifd = open(in, O_RDONLY); |
|
if (ifd < 0) { |
if (verbose >= 0) |
if (verbose >= 0) |
warn("%s", in); |
warn("%s", in); |
return -1; |
return -1; |
|
|
} |
} |
|
|
/* XXX - open constrains outfile to MAXPATHLEN so this is safe */ |
/* XXX - open constrains outfile to MAXPATHLEN so this is safe */ |
if ((cookie = (*method->open)(ifd, "r", nosave ? NULL : out, |
oldname[0] = '\0'; |
bits, 0, 1)) == NULL) { |
if ((cookie = (*method->open)(ifd, "r", oldname, bits, 0, 1)) == NULL) { |
if (verbose >= 0) |
if (verbose >= 0) |
warn("%s", in); |
warn("%s", in); |
close (ifd); |
close (ifd); |
return (FAILURE); |
return (FAILURE); |
} |
} |
|
if (!nosave && oldname[0] != '\0') { |
|
strlcpy(out, oldname, MAXPATHLEN); |
|
cat = 0; /* XXX should -c override? */ |
|
} |
|
|
if (testmode) |
if (testmode) |
ofd = -1; |
ofd = -1; |
else if ((ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR)) < 0) { |
else { |
if (verbose >= 0) |
if (cat) |
warn("%s", in); |
ofd = dup(STDOUT_FILENO); |
(method->close)(cookie, NULL, NULL, NULL); |
else { |
return (FAILURE); |
if (stat(out, &osb) == 0) { |
|
oreg = S_ISREG(osb.st_mode); |
|
if (!force && oreg && !permission(out)) { |
|
(void) close(ifd); |
|
return (WARNING); |
|
} |
|
} |
|
ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR); |
|
} |
|
if (ofd < 0) { |
|
if (verbose >= 0) |
|
warn("%s", in); |
|
(method->close)(cookie, NULL, NULL, NULL); |
|
return (FAILURE); |
|
} |
} |
} |
|
|
while ((nr = (method->read)(cookie, buf, sizeof(buf))) > 0) { |
while ((nr = (method->read)(cookie, buf, sizeof(buf))) > 0) { |
|
|
warnx("%s", in); |
warnx("%s", in); |
error = FAILURE; |
error = FAILURE; |
} |
} |
if (!nosave) { |
if (!nosave && !cat) { |
if (info.mtime != 0) { |
if (info.mtime != 0) { |
sb->st_mtimespec.tv_sec = |
sb->st_mtimespec.tv_sec = |
sb->st_atimespec.tv_sec = info.mtime; |
sb->st_atimespec.tv_sec = info.mtime; |
|
|
sb->st_atimespec.tv_nsec = 0; |
sb->st_atimespec.tv_nsec = 0; |
} else |
} else |
nosave = 1; /* no timestamp to restore */ |
nosave = 1; /* no timestamp to restore */ |
|
|
if (cat && strcmp(out, "/dev/stdout") != 0) |
|
cat = 0; /* have a real output name */ |
|
} |
} |
if (error == SUCCESS) |
if (error == SUCCESS) |
setfile(out, ofd, sb); |
setfile(out, ofd, sb); |
|
|
} |
} |
} |
} |
|
|
|
/* On error, clean up the file we created but preserve errno. */ |
|
if (error && oreg) |
|
unlink(out); |
|
|
return (error); |
return (error); |
} |
} |
|
|
|
|
nruns++; |
nruns++; |
|
|
if (name != NULL) { |
if (name != NULL) { |
if (strcmp(name, "/dev/stdout") == 0) |
|
name += 5; |
|
if (verbose > 0) { |
if (verbose > 0) { |
timestr = ctime(&info->mtime) + 4; |
timestr = ctime(&info->mtime) + 4; |
timestr[12] = '\0'; |
timestr[12] = '\0'; |