[hackers] [sbase] tar: Use raw I/O instead of standard file streams || sin

From: <git_AT_suckless.org>
Date: Thu, 23 Apr 2015 16:32:06 +0200 (CEST)

commit ab267a87ebf9e8819cd604b3daa12ad6c68b71aa
Author: sin <sin_AT_2f30.org>
Date: Thu Apr 23 15:20:10 2015 +0100

    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.

diff --git a/tar.c b/tar.c
index c906f0f..cb3d17d 100644
--- a/tar.c
+++ b/tar.c
_AT_@ -3,6 +3,7 @@
 #include <sys/time.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <grp.h>
 #include <libgen.h>
 #include <pwd.h>
_AT_@ -47,8 +48,7 @@ enum Type {
         BLOCKDEV = '4', DIRECTORY = '5', FIFO = '6'
 };
 
-static FILE *tarfile;
-static char *tarfilename;
+static int tarfd;
 static ino_t tarinode;
 static dev_t tardev;
 
_AT_@ -59,6 +59,7 @@ static struct ent {
         char *name;
         time_t mtime;
 } *ents;
+
 static size_t entlen;
 
 static void
_AT_@ -80,8 +81,8 @@ popent(void)
         return NULL;
 }
 
-static FILE *
-decomp(FILE *fp)
+static int
+decomp(int fd)
 {
         int fds[2];
         char *tool;
_AT_@ -93,7 +94,7 @@ decomp(FILE *fp)
         case -1:
                 eprintf("fork:");
         case 0:
- dup2(fileno(fp), 0);
+ dup2(fd, 0);
                 dup2(fds[1], 1);
                 close(fds[0]);
                 close(fds[1]);
_AT_@ -104,8 +105,32 @@ decomp(FILE *fp)
                 _exit(1);
         }
         close(fds[1]);
+ return fds[0];
+}
+
+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;
+}
 
- return fdopen(fds[0], "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
_AT_@ -118,14 +143,14 @@ putoctal(char *dst, unsigned num, int size)
 static int
 archive(const char *path)
 {
- FILE *f = NULL;
+ unsigned char b[BLKSIZ];
         struct group *gr;
         struct header *h;
         struct passwd *pw;
         struct stat st;
         size_t chksum, x;
         ssize_t l, r;
- unsigned char b[BLKSIZ];
+ int fd = -1;
 
         if (lstat(path, &st) < 0) {
                 weprintf("lstat %s:", path);
_AT_@ -154,7 +179,9 @@ archive(const char *path)
         if (S_ISREG(st.st_mode)) {
                 h->type = REG;
                 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)) {
                 h->type = DIRECTORY;
         } else if (S_ISLNK(st.st_mode)) {
_AT_@ -174,18 +201,15 @@ archive(const char *path)
         for (x = 0, chksum = 0; x < sizeof(*h); x++)
                 chksum += b[x];
         putoctal(h->chksum, chksum, sizeof(h->chksum));
+ ewrite(tarfd, b, BLKSIZ);
 
- if (fwrite(b, BLKSIZ, 1, tarfile) != 1)
- eprintf("fwrite:");
-
- if (f) {
- while ((l = fread(b, 1, BLKSIZ, f)) > 0) {
+ if (fd != -1) {
+ while ((l = eread(fd, b, BLKSIZ)) > 0) {
                         if (l < BLKSIZ)
                                 memset(b + l, 0, BLKSIZ - l);
- if (fwrite(b, BLKSIZ, 1, tarfile) != 1)
- eprintf("fwrite:");
+ ewrite(tarfd, b, BLKSIZ);
                 }
- efshut(f, path);
+ close(fd);
         }
 
         return 0;
_AT_@ -194,10 +218,10 @@ archive(const char *path)
 static int
 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;
+ 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'))
                 eprintf("strtol %s: invalid number\n", h->mtime);
_AT_@ -213,10 +237,11 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
         case AREG:
                 if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
                         eprintf("strtol %s: invalid number\n", h->mode);
- if (!(f = fopen(fname, "w")))
- eprintf("fopen %s:", fname);
- if (chmod(fname, mode) < 0)
- eprintf("chmod %s:", fname);
+ fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0644);
+ if (fd < 0)
+ eprintf("open %s:", fname);
+ if (fchmod(fd, mode) < 0)
+ eprintf("fchmod %s:", fname);
                 break;
         case HARDLINK:
         case SYMLINK:
_AT_@ -262,14 +287,12 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
         if (!getuid() && chown(fname, uid, gid))
                 weprintf("chown %s:", fname);
 
- for (; l > 0; l -= BLKSIZ) {
- if (fread(b, BLKSIZ, 1, tarfile) != 1)
- eprintf("fread %s:", tarfilename);
- if (f && fwrite(b, MIN(l, BLKSIZ), 1, f) != 1)
- eprintf("fwrite %s:", fname);
+ if (fd != -1) {
+ for (; l > 0; l -= BLKSIZ)
+ if (eread(tarfd, b, BLKSIZ) > 0)
+ ewrite(fd, b, MIN(l, BLKSIZ));
+ close(fd);
         }
- if (f)
- fshut(f, fname);
 
         pushent(fname, mtime);
         return 0;
_AT_@ -281,8 +304,8 @@ skipblk(ssize_t l)
         char b[BLKSIZ];
 
         for (; l > 0; l -= BLKSIZ)
- if (fread(b, BLKSIZ, 1, tarfile) != 1)
- eprintf("fread %s:", tarfilename);
+ if (!eread(tarfd, b, BLKSIZ))
+ break;
 }
 
 static int
_AT_@ -339,7 +362,7 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
         long size;
         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;
 
                 /* small dance around non-null terminated fields */
_AT_@ -371,8 +394,6 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
 
                 fn(fname, size, b);
         }
- if (ferror(tarfile))
- eprintf("fread %s:", tarfilename);
 
         if (!mflag) {
                 while ((ent = popent())) {
_AT_@ -397,11 +418,11 @@ usage(void)
 int
 main(int argc, char *argv[])
 {
- FILE *fp;
         struct recursor r = { .fn = c, .hist = NULL, .depth = 0, .maxdepth = 0,
                               .follow = 'P', .flags = DIRFIRST };
         struct stat st;
         char *file = NULL, *dir = ".", mode = '\0';
+ int fd;
 
         ARGBEGIN {
         case 'x':
_AT_@ -437,19 +458,17 @@ main(int argc, char *argv[])
 
         switch (mode) {
         case 'c':
+ tarfd = 1;
                 if (file) {
- if (!(fp = fopen(file, "w")))
- eprintf("fopen %s:", file);
+ tarfd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
+ if (tarfd < 0)
+ eprintf("open %s:", file);
                         if (lstat(file, &st) < 0)
                                 eprintf("lstat %s:", file);
                         tarinode = st.st_ino;
                         tardev = st.st_dev;
- tarfile = fp;
- tarfilename = file;
- } else {
- tarfile = stdout;
- tarfilename = "<stdout>";
                 }
+
                 if (chdir(dir) < 0)
                         eprintf("chdir %s:", dir);
                 for (; *argv; argc--, argv++)
_AT_@ -457,22 +476,19 @@ main(int argc, char *argv[])
                 break;
         case 't':
         case 'x':
+ tarfd = 0;
                 if (file) {
- if (!(fp = fopen(file, "r")))
- eprintf("fopen %s:", file);
- } else {
- fp = stdin;
+ tarfd = open(file, O_RDONLY);
+ if (tarfd < 0)
+ eprintf("open %s:", file);
                 }
 
- tarfilename = file;
-
                 switch (filtermode) {
                 case 'j':
                 case 'z':
- tarfile = decomp(fp);
- break;
- default:
- tarfile = fp;
+ fd = tarfd;
+ tarfd = decomp(tarfd);
+ close(fd);
                         break;
                 }
 
Received on Thu Apr 23 2015 - 16:32:06 CEST

This archive was generated by hypermail 2.3.0 : Thu Apr 23 2015 - 16:36:14 CEST