tar: Use raw I/O instead of standard file streams
As part of refactoring tar to add support for compression through gzip/bzip2, it makes sense to avoid intermixing file stream I/O with raw I/O.
This commit is contained in:
parent
fb1595a69c
commit
ab267a87eb
124
tar.c
124
tar.c
|
@ -3,6 +3,7 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
@ -47,8 +48,7 @@ enum Type {
|
||||||
BLOCKDEV = '4', DIRECTORY = '5', FIFO = '6'
|
BLOCKDEV = '4', DIRECTORY = '5', FIFO = '6'
|
||||||
};
|
};
|
||||||
|
|
||||||
static FILE *tarfile;
|
static int tarfd;
|
||||||
static char *tarfilename;
|
|
||||||
static ino_t tarinode;
|
static ino_t tarinode;
|
||||||
static dev_t tardev;
|
static dev_t tardev;
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ static struct ent {
|
||||||
char *name;
|
char *name;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
} *ents;
|
} *ents;
|
||||||
|
|
||||||
static size_t entlen;
|
static size_t entlen;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -80,8 +81,8 @@ popent(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE *
|
static int
|
||||||
decomp(FILE *fp)
|
decomp(int fd)
|
||||||
{
|
{
|
||||||
int fds[2];
|
int fds[2];
|
||||||
char *tool;
|
char *tool;
|
||||||
|
@ -93,7 +94,7 @@ decomp(FILE *fp)
|
||||||
case -1:
|
case -1:
|
||||||
eprintf("fork:");
|
eprintf("fork:");
|
||||||
case 0:
|
case 0:
|
||||||
dup2(fileno(fp), 0);
|
dup2(fd, 0);
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
close(fds[0]);
|
close(fds[0]);
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
|
@ -104,8 +105,32 @@ decomp(FILE *fp)
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
|
return fds[0];
|
||||||
|
}
|
||||||
|
|
||||||
return fdopen(fds[0], "r");
|
static ssize_t
|
||||||
|
eread(int fd, void *buf, size_t n)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
again:
|
||||||
|
r = read(fd, buf, n);
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto again;
|
||||||
|
eprintf("read:");
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
ewrite(int fd, const void *buf, size_t n)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
if ((r = write(fd, buf, n)) != n)
|
||||||
|
eprintf("write:");
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -118,14 +143,14 @@ putoctal(char *dst, unsigned num, int size)
|
||||||
static int
|
static int
|
||||||
archive(const char *path)
|
archive(const char *path)
|
||||||
{
|
{
|
||||||
FILE *f = NULL;
|
unsigned char b[BLKSIZ];
|
||||||
struct group *gr;
|
struct group *gr;
|
||||||
struct header *h;
|
struct header *h;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
size_t chksum, x;
|
size_t chksum, x;
|
||||||
ssize_t l, r;
|
ssize_t l, r;
|
||||||
unsigned char b[BLKSIZ];
|
int fd = -1;
|
||||||
|
|
||||||
if (lstat(path, &st) < 0) {
|
if (lstat(path, &st) < 0) {
|
||||||
weprintf("lstat %s:", path);
|
weprintf("lstat %s:", path);
|
||||||
|
@ -154,7 +179,9 @@ archive(const char *path)
|
||||||
if (S_ISREG(st.st_mode)) {
|
if (S_ISREG(st.st_mode)) {
|
||||||
h->type = REG;
|
h->type = REG;
|
||||||
putoctal(h->size, (unsigned)st.st_size, sizeof(h->size));
|
putoctal(h->size, (unsigned)st.st_size, sizeof(h->size));
|
||||||
f = fopen(path, "r");
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
eprintf("open %s:", path);
|
||||||
} else if (S_ISDIR(st.st_mode)) {
|
} else if (S_ISDIR(st.st_mode)) {
|
||||||
h->type = DIRECTORY;
|
h->type = DIRECTORY;
|
||||||
} else if (S_ISLNK(st.st_mode)) {
|
} else if (S_ISLNK(st.st_mode)) {
|
||||||
|
@ -174,18 +201,15 @@ archive(const char *path)
|
||||||
for (x = 0, chksum = 0; x < sizeof(*h); x++)
|
for (x = 0, chksum = 0; x < sizeof(*h); x++)
|
||||||
chksum += b[x];
|
chksum += b[x];
|
||||||
putoctal(h->chksum, chksum, sizeof(h->chksum));
|
putoctal(h->chksum, chksum, sizeof(h->chksum));
|
||||||
|
ewrite(tarfd, b, BLKSIZ);
|
||||||
|
|
||||||
if (fwrite(b, BLKSIZ, 1, tarfile) != 1)
|
if (fd != -1) {
|
||||||
eprintf("fwrite:");
|
while ((l = eread(fd, b, BLKSIZ)) > 0) {
|
||||||
|
|
||||||
if (f) {
|
|
||||||
while ((l = fread(b, 1, BLKSIZ, f)) > 0) {
|
|
||||||
if (l < BLKSIZ)
|
if (l < BLKSIZ)
|
||||||
memset(b + l, 0, BLKSIZ - l);
|
memset(b + l, 0, BLKSIZ - l);
|
||||||
if (fwrite(b, BLKSIZ, 1, tarfile) != 1)
|
ewrite(tarfd, b, BLKSIZ);
|
||||||
eprintf("fwrite:");
|
|
||||||
}
|
}
|
||||||
efshut(f, path);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -194,10 +218,10 @@ archive(const char *path)
|
||||||
static int
|
static int
|
||||||
unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
||||||
{
|
{
|
||||||
FILE *f = NULL;
|
|
||||||
struct header *h = (struct header *)b;
|
|
||||||
long mode, major, minor, type, mtime, uid, gid;
|
|
||||||
char lname[101], *tmp, *p;
|
char lname[101], *tmp, *p;
|
||||||
|
long mode, major, minor, type, mtime, uid, gid;
|
||||||
|
struct header *h = (struct header *)b;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0'))
|
if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0'))
|
||||||
eprintf("strtol %s: invalid number\n", h->mtime);
|
eprintf("strtol %s: invalid number\n", h->mtime);
|
||||||
|
@ -213,10 +237,11 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
||||||
case AREG:
|
case AREG:
|
||||||
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->mode);
|
eprintf("strtol %s: invalid number\n", h->mode);
|
||||||
if (!(f = fopen(fname, "w")))
|
fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0644);
|
||||||
eprintf("fopen %s:", fname);
|
if (fd < 0)
|
||||||
if (chmod(fname, mode) < 0)
|
eprintf("open %s:", fname);
|
||||||
eprintf("chmod %s:", fname);
|
if (fchmod(fd, mode) < 0)
|
||||||
|
eprintf("fchmod %s:", fname);
|
||||||
break;
|
break;
|
||||||
case HARDLINK:
|
case HARDLINK:
|
||||||
case SYMLINK:
|
case SYMLINK:
|
||||||
|
@ -262,14 +287,12 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
||||||
if (!getuid() && chown(fname, uid, gid))
|
if (!getuid() && chown(fname, uid, gid))
|
||||||
weprintf("chown %s:", fname);
|
weprintf("chown %s:", fname);
|
||||||
|
|
||||||
for (; l > 0; l -= BLKSIZ) {
|
if (fd != -1) {
|
||||||
if (fread(b, BLKSIZ, 1, tarfile) != 1)
|
for (; l > 0; l -= BLKSIZ)
|
||||||
eprintf("fread %s:", tarfilename);
|
if (eread(tarfd, b, BLKSIZ) > 0)
|
||||||
if (f && fwrite(b, MIN(l, BLKSIZ), 1, f) != 1)
|
ewrite(fd, b, MIN(l, BLKSIZ));
|
||||||
eprintf("fwrite %s:", fname);
|
close(fd);
|
||||||
}
|
}
|
||||||
if (f)
|
|
||||||
fshut(f, fname);
|
|
||||||
|
|
||||||
pushent(fname, mtime);
|
pushent(fname, mtime);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -281,8 +304,8 @@ skipblk(ssize_t l)
|
||||||
char b[BLKSIZ];
|
char b[BLKSIZ];
|
||||||
|
|
||||||
for (; l > 0; l -= BLKSIZ)
|
for (; l > 0; l -= BLKSIZ)
|
||||||
if (fread(b, BLKSIZ, 1, tarfile) != 1)
|
if (!eread(tarfd, b, BLKSIZ))
|
||||||
eprintf("fread %s:", tarfilename);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -339,7 +362,7 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
|
||||||
long size;
|
long size;
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
while (fread(b, BLKSIZ, 1, tarfile) == 1 && *h->name) {
|
while (eread(tarfd, b, BLKSIZ) > 0 && h->name[0]) {
|
||||||
sanitize(h), n = 0;
|
sanitize(h), n = 0;
|
||||||
|
|
||||||
/* small dance around non-null terminated fields */
|
/* small dance around non-null terminated fields */
|
||||||
|
@ -371,8 +394,6 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
|
||||||
|
|
||||||
fn(fname, size, b);
|
fn(fname, size, b);
|
||||||
}
|
}
|
||||||
if (ferror(tarfile))
|
|
||||||
eprintf("fread %s:", tarfilename);
|
|
||||||
|
|
||||||
if (!mflag) {
|
if (!mflag) {
|
||||||
while ((ent = popent())) {
|
while ((ent = popent())) {
|
||||||
|
@ -397,11 +418,11 @@ usage(void)
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
struct recursor r = { .fn = c, .hist = NULL, .depth = 0, .maxdepth = 0,
|
struct recursor r = { .fn = c, .hist = NULL, .depth = 0, .maxdepth = 0,
|
||||||
.follow = 'P', .flags = DIRFIRST };
|
.follow = 'P', .flags = DIRFIRST };
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *file = NULL, *dir = ".", mode = '\0';
|
char *file = NULL, *dir = ".", mode = '\0';
|
||||||
|
int fd;
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case 'x':
|
case 'x':
|
||||||
|
@ -437,19 +458,17 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 'c':
|
case 'c':
|
||||||
|
tarfd = 1;
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!(fp = fopen(file, "w")))
|
tarfd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
|
||||||
eprintf("fopen %s:", file);
|
if (tarfd < 0)
|
||||||
|
eprintf("open %s:", file);
|
||||||
if (lstat(file, &st) < 0)
|
if (lstat(file, &st) < 0)
|
||||||
eprintf("lstat %s:", file);
|
eprintf("lstat %s:", file);
|
||||||
tarinode = st.st_ino;
|
tarinode = st.st_ino;
|
||||||
tardev = st.st_dev;
|
tardev = st.st_dev;
|
||||||
tarfile = fp;
|
|
||||||
tarfilename = file;
|
|
||||||
} else {
|
|
||||||
tarfile = stdout;
|
|
||||||
tarfilename = "<stdout>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chdir(dir) < 0)
|
if (chdir(dir) < 0)
|
||||||
eprintf("chdir %s:", dir);
|
eprintf("chdir %s:", dir);
|
||||||
for (; *argv; argc--, argv++)
|
for (; *argv; argc--, argv++)
|
||||||
|
@ -457,22 +476,19 @@ main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
case 'x':
|
case 'x':
|
||||||
|
tarfd = 0;
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!(fp = fopen(file, "r")))
|
tarfd = open(file, O_RDONLY);
|
||||||
eprintf("fopen %s:", file);
|
if (tarfd < 0)
|
||||||
} else {
|
eprintf("open %s:", file);
|
||||||
fp = stdin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tarfilename = file;
|
|
||||||
|
|
||||||
switch (filtermode) {
|
switch (filtermode) {
|
||||||
case 'j':
|
case 'j':
|
||||||
case 'z':
|
case 'z':
|
||||||
tarfile = decomp(fp);
|
fd = tarfd;
|
||||||
break;
|
tarfd = decomp(tarfd);
|
||||||
default:
|
close(fd);
|
||||||
tarfile = fp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user