]> www.infradead.org Git - users/hch/misc.git/commitdiff
gen_init_cpio: write to fd instead of stdout stream
authorDavid Disseldorp <ddiss@suse.de>
Tue, 19 Aug 2025 03:05:44 +0000 (13:05 +1000)
committerNathan Chancellor <nathan@kernel.org>
Wed, 20 Aug 2025 23:02:55 +0000 (16:02 -0700)
In preparation for more efficient archiving using copy_file_range(),
switch from writing archive data to stdout to using STDOUT_FILENO and
I/O via write(), dprintf(), etc.
Basic I/O error handling is added to cover cases such as ENOSPC. Partial
writes are treated as errors.

Signed-off-by: David Disseldorp <ddiss@suse.de>
Reviewed-by: Nicolas Schier <nsc@kernel.org>
Link: https://lore.kernel.org/r/20250819032607.28727-2-ddiss@suse.de
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
usr/gen_init_cpio.c

index edcdb8abfa31ca82e2cb506e2c7749ad8116e7e0..235bfc574e6b1799a2f5f8ca857f0f3109889e6d 100644 (file)
 #define xstr(s) #s
 #define str(s) xstr(s)
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define CPIO_HDR_LEN 110
+#define padlen(_off, _align) (((_align) - ((_off) & ((_align) - 1))) % (_align))
 
+static char padding[512];
 static unsigned int offset;
 static unsigned int ino = 721;
 static time_t default_mtime;
 static bool do_file_mtime;
 static bool do_csum = false;
+static int outfd = STDOUT_FILENO;
 
 struct file_handler {
        const char *type;
        int (*handler)(const char *line);
 };
 
-static void push_string(const char *name)
+static int push_string(const char *name)
 {
        unsigned int name_len = strlen(name) + 1;
+       ssize_t len;
+
+       len = write(outfd, name, name_len);
+       if (len != name_len)
+               return -1;
 
-       fputs(name, stdout);
-       putchar(0);
        offset += name_len;
+       return 0;
 }
 
-static void push_pad (void)
+static int push_pad(size_t padlen)
 {
-       while (offset & 3) {
-               putchar(0);
-               offset++;
-       }
+       ssize_t len = 0;
+
+       if (!padlen)
+               return 0;
+
+       if (padlen < sizeof(padding))
+               len = write(outfd, padding, padlen);
+       if (len != padlen)
+               return -1;
+
+       offset += padlen;
+       return 0;
 }
 
-static void push_rest(const char *name)
+static int push_rest(const char *name)
 {
        unsigned int name_len = strlen(name) + 1;
-       unsigned int tmp_ofs;
+       ssize_t len;
 
-       fputs(name, stdout);
-       putchar(0);
-       offset += name_len;
+       len = write(outfd, name, name_len);
+       if (len != name_len)
+               return -1;
 
-       tmp_ofs = name_len + 110;
-       while (tmp_ofs & 3) {
-               putchar(0);
-               offset++;
-               tmp_ofs++;
-       }
-}
+       offset += name_len;
 
-static void push_hdr(const char *s)
-{
-       fputs(s, stdout);
-       offset += 110;
+       return push_pad(padlen(name_len + CPIO_HDR_LEN, 4));
 }
 
-static void cpio_trailer(void)
+static int cpio_trailer(void)
 {
-       char s[256];
        const char name[] = "TRAILER!!!";
+       int len;
 
-       sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
+       len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                do_csum ? "070702" : "070701", /* magic */
                0,                      /* ino */
@@ -96,23 +103,24 @@ static void cpio_trailer(void)
                0,                      /* rminor */
                (unsigned)strlen(name)+1, /* namesize */
                0);                     /* chksum */
-       push_hdr(s);
-       push_rest(name);
+       offset += len;
 
-       while (offset % 512) {
-               putchar(0);
-               offset++;
-       }
+       if (len != CPIO_HDR_LEN ||
+           push_rest(name) < 0 ||
+           push_pad(padlen(offset, 512)) < 0)
+               return -1;
+
+       return 0;
 }
 
 static int cpio_mkslink(const char *name, const char *target,
                         unsigned int mode, uid_t uid, gid_t gid)
 {
-       char s[256];
+       int len;
 
        if (name[0] == '/')
                name++;
-       sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+       len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                do_csum ? "070702" : "070701", /* magic */
                ino++,                  /* ino */
@@ -128,12 +136,17 @@ static int cpio_mkslink(const char *name, const char *target,
                0,                      /* rminor */
                (unsigned)strlen(name) + 1,/* namesize */
                0);                     /* chksum */
-       push_hdr(s);
-       push_string(name);
-       push_pad();
-       push_string(target);
-       push_pad();
+       offset += len;
+
+       if (len != CPIO_HDR_LEN ||
+           push_string(name) < 0 ||
+           push_pad(padlen(offset, 4)) < 0 ||
+           push_string(target) < 0 ||
+           push_pad(padlen(offset, 4)) < 0)
+               return -1;
+
        return 0;
+
 }
 
 static int cpio_mkslink_line(const char *line)
@@ -157,11 +170,11 @@ static int cpio_mkslink_line(const char *line)
 static int cpio_mkgeneric(const char *name, unsigned int mode,
                       uid_t uid, gid_t gid)
 {
-       char s[256];
+       int len;
 
        if (name[0] == '/')
                name++;
-       sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+       len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                do_csum ? "070702" : "070701", /* magic */
                ino++,                  /* ino */
@@ -177,8 +190,12 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
                0,                      /* rminor */
                (unsigned)strlen(name) + 1,/* namesize */
                0);                     /* chksum */
-       push_hdr(s);
-       push_rest(name);
+       offset += len;
+
+       if (len != CPIO_HDR_LEN ||
+           push_rest(name) < 0)
+               return -1;
+
        return 0;
 }
 
@@ -246,7 +263,7 @@ static int cpio_mknod(const char *name, unsigned int mode,
                       uid_t uid, gid_t gid, char dev_type,
                       unsigned int maj, unsigned int min)
 {
-       char s[256];
+       int len;
 
        if (dev_type == 'b')
                mode |= S_IFBLK;
@@ -255,7 +272,7 @@ static int cpio_mknod(const char *name, unsigned int mode,
 
        if (name[0] == '/')
                name++;
-       sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+       len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                do_csum ? "070702" : "070701", /* magic */
                ino++,                  /* ino */
@@ -271,8 +288,12 @@ static int cpio_mknod(const char *name, unsigned int mode,
                min,                    /* rminor */
                (unsigned)strlen(name) + 1,/* namesize */
                0);                     /* chksum */
-       push_hdr(s);
-       push_rest(name);
+       offset += len;
+
+       if (len != CPIO_HDR_LEN ||
+           push_rest(name) < 0)
+               return -1;
+
        return 0;
 }
 
@@ -324,11 +345,9 @@ static int cpio_mkfile(const char *name, const char *location,
                        unsigned int mode, uid_t uid, gid_t gid,
                        unsigned int nlinks)
 {
-       char s[256];
        struct stat buf;
        unsigned long size;
-       int file;
-       int retval;
+       int file, retval, len;
        int rc = -1;
        time_t mtime;
        int namesize;
@@ -386,7 +405,7 @@ static int cpio_mkfile(const char *name, const char *location,
                if (name[0] == '/')
                        name++;
                namesize = strlen(name) + 1;
-               sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+               len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
                       "%08lX%08X%08X%08X%08X%08X%08X",
                        do_csum ? "070702" : "070701", /* magic */
                        ino,                    /* ino */
@@ -402,9 +421,12 @@ static int cpio_mkfile(const char *name, const char *location,
                        0,                      /* rminor */
                        namesize,               /* namesize */
                        size ? csum : 0);       /* chksum */
-               push_hdr(s);
-               push_string(name);
-               push_pad();
+               offset += len;
+
+               if (len != CPIO_HDR_LEN ||
+                   push_string(name) < 0 ||
+                   push_pad(padlen(offset, 4)) < 0)
+                       goto error;
 
                while (size) {
                        unsigned char filebuf[65536];
@@ -417,14 +439,15 @@ static int cpio_mkfile(const char *name, const char *location,
                                goto error;
                        }
 
-                       if (fwrite(filebuf, this_read, 1, stdout) != 1) {
+                       if (write(outfd, filebuf, this_read) != this_read) {
                                fprintf(stderr, "writing filebuf failed\n");
                                goto error;
                        }
                        offset += this_read;
                        size -= this_read;
                }
-               push_pad();
+               if (push_pad(padlen(offset, 4)) < 0)
+                       goto error;
 
                name += namesize;
        }
@@ -691,7 +714,7 @@ int main (int argc, char *argv[])
                }
        }
        if (ec == 0)
-               cpio_trailer();
+               ec = cpio_trailer();
 
        exit(ec);
 }