[Libguestfs] [PATCH febootstrap 4/8] Refactor cpio code into separate file.

Richard W.M. Jones rjones at redhat.com
Fri Aug 20 10:40:11 UTC 2010


-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://et.redhat.com/~rjones/libguestfs/
See what it can do: http://et.redhat.com/~rjones/libguestfs/recipes.html
-------------- next part --------------
>From a241e323e209b0da30396408574c8e3d89b323e0 Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at redhat.com>
Date: Thu, 19 Aug 2010 14:23:11 +0100
Subject: [PATCH 4/8] Refactor cpio code into separate file.

We create a 'writer' abstraction and (currently) a single implementation
of this which can write cpio files.  All cpio-related code is moved
out of 'appliance.c' into 'cpio.c'.  'appliance.c' becomes a generic
appliance builder.

This commit should not change the semantics of the program.
---
 helper/Makefile.am |    1 +
 helper/appliance.c |  274 +++++----------------------------------------------
 helper/cpio.c      |  278 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 helper/helper.h    |   26 +++++-
 helper/main.c      |    3 +-
 5 files changed, 333 insertions(+), 249 deletions(-)
 create mode 100644 helper/cpio.c

diff --git a/helper/Makefile.am b/helper/Makefile.am
index fb21286..985d4b2 100644
--- a/helper/Makefile.am
+++ b/helper/Makefile.am
@@ -24,6 +24,7 @@ DISTCLEANFILES = $(bin_SCRIPTS)
 febootstrap_supermin_helper_SOURCES = \
 	helper.h \
 	appliance.c \
+	cpio.c \
 	kernel.c \
 	main.c \
 	utils.c
diff --git a/helper/appliance.c b/helper/appliance.c
index c6defc0..b7a46c0 100644
--- a/helper/appliance.c
+++ b/helper/appliance.c
@@ -22,7 +22,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <limits.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <dirent.h>
@@ -32,32 +31,15 @@
 
 #include "error.h"
 #include "fts_.h"
-#include "full-write.h"
 #include "xalloc.h"
 #include "xvasprintf.h"
 
 #include "helper.h"
 
-/* Buffer size used in copy operations throughout.  Large for
- * greatest efficiency.
- */
-#define BUFFER_SIZE 65536
-
-static void iterate_inputs (char **inputs, int nr_inputs);
-static void iterate_input_directory (const char *dirname, int dirfd);
-static void write_kernel_modules (const char *whitelist, const char *modpath);
-static void write_hostfiles (const char *hostfiles_file);
-static void write_to_fd (const void *buffer, size_t len);
-static void write_file_to_fd (const char *filename);
-static void write_file_len_to_fd (const char *filename, size_t len);
-static void write_padding (size_t len);
-static void cpio_append_fts_entry (FTSENT *entry);
-static void cpio_append_stat (const char *filename, struct stat *);
-static void cpio_append (const char *filename);
-static void cpio_append_trailer (void);
-
-static int out_fd = -1;
-static off_t out_offset = 0;
+static void iterate_inputs (char **inputs, int nr_inputs, struct writer *);
+static void iterate_input_directory (const char *dirname, int dirfd, struct writer *);
+static void add_kernel_modules (const char *whitelist, const char *modpath, struct writer *);
+static void add_hostfiles (const char *hostfiles_file, struct writer *);
 
 /* Create the appliance.
  *
@@ -86,30 +68,24 @@ void
 create_appliance (char **inputs, int nr_inputs,
                   const char *whitelist,
                   const char *modpath,
-                  const char *appliance)
+                  const char *appliance,
+                  struct writer *writer)
 {
-  out_fd = open (appliance, O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY, 0644);
-  if (out_fd == -1)
-    error (EXIT_FAILURE, errno, "open: %s", appliance);
-  out_offset = 0;
+  writer->wr_start (appliance);
 
-  iterate_inputs (inputs, nr_inputs);
+  iterate_inputs (inputs, nr_inputs, writer);
 
   /* Kernel modules (3). */
-  write_kernel_modules (whitelist, modpath);
-
-  cpio_append_trailer ();
+  add_kernel_modules (whitelist, modpath, writer);
 
-  /* Finish off and close output file. */
-  if (close (out_fd) == -1)
-    error (EXIT_FAILURE, errno, "close: %s", appliance);
+  writer->wr_end ();
 }
 
 /* Iterate over the inputs to find out what they are, visiting
  * directories if specified.
  */
 static void
-iterate_inputs (char **inputs, int nr_inputs)
+iterate_inputs (char **inputs, int nr_inputs, struct writer *writer)
 {
   int i;
   for (i = 0; i < nr_inputs; ++i) {
@@ -126,16 +102,16 @@ iterate_inputs (char **inputs, int nr_inputs)
 
     /* Directory? */
     if (S_ISDIR (statbuf.st_mode))
-      iterate_input_directory (inputs[i], fd);
+      iterate_input_directory (inputs[i], fd, writer);
     else if (S_ISREG (statbuf.st_mode)) {
       /* Is it a cpio file? */
       char buf[6];
       if (read (fd, buf, 6) == 6 && memcmp (buf, "070701", 6) == 0)
         /* Yes, a cpio file.  This is a skeleton appliance, case (1). */
-        write_file_to_fd (inputs[i]);
+        writer->wr_cpio_file (inputs[i]);
       else
         /* No, must be hostfiles, case (2). */
-        write_hostfiles (inputs[i]);
+        add_hostfiles (inputs[i], writer);
     }
     else
       error (EXIT_FAILURE, 0, "%s: input is not a regular file or directory",
@@ -146,7 +122,7 @@ iterate_inputs (char **inputs, int nr_inputs)
 }
 
 static void
-iterate_input_directory (const char *dirname, int dirfd)
+iterate_input_directory (const char *dirname, int dirfd, struct writer *writer)
 {
   char path[PATH_MAX];
   strcpy (path, dirname);
@@ -165,7 +141,7 @@ iterate_input_directory (const char *dirname, int dirfd)
       continue;
 
     strcpy (&path[len], d->d_name);
-    iterate_inputs (inputs, 1);
+    iterate_inputs (inputs, 1, writer);
   }
 
   if (errno != 0)
@@ -188,7 +164,8 @@ iterate_input_directory (const char *dirname, int dirfd)
  * whitelist_file may be NULL, to include ALL kernel modules.
  */
 static void
-write_kernel_modules (const char *whitelist_file, const char *modpath)
+add_kernel_modules (const char *whitelist_file, const char *modpath,
+                    struct writer *writer)
 {
   char **whitelist = NULL;
   if (whitelist_file != NULL)
@@ -197,13 +174,13 @@ write_kernel_modules (const char *whitelist_file, const char *modpath)
   char *paths[2] = { (char *) modpath, NULL };
   FTS *fts = fts_open (paths, FTS_COMFOLLOW|FTS_PHYSICAL, NULL);
   if (fts == NULL)
-    error (EXIT_FAILURE, errno, "write_kernel_modules: fts_open: %s", modpath);
+    error (EXIT_FAILURE, errno, "add_kernel_modules: fts_open: %s", modpath);
 
   for (;;) {
     errno = 0;
     FTSENT *entry = fts_read (fts);
     if (entry == NULL && errno != 0)
-      error (EXIT_FAILURE, errno, "write_kernel_modules: fts_read: %s", modpath);
+      error (EXIT_FAILURE, errno, "add_kernel_modules: fts_read: %s", modpath);
     if (entry == NULL)
       break;
 
@@ -227,7 +204,7 @@ write_kernel_modules (const char *whitelist_file, const char *modpath)
             if (verbose >= 2)
               fprintf (stderr, "including kernel module %s (matches whitelist entry %s)\n",
                        entry->fts_name, whitelist[j]);
-            cpio_append_fts_entry (entry);
+            writer->wr_fts_entry (entry);
             break;
           } else if (r != FNM_NOMATCH)
             error (EXIT_FAILURE, 0, "internal error: fnmatch ('%s', '%s', %d) returned unexpected non-zero value %d\n",
@@ -236,15 +213,15 @@ write_kernel_modules (const char *whitelist_file, const char *modpath)
       } else { /* whitelist == NULL, always include */
         if (verbose >= 2)
           fprintf (stderr, "including kernel module %s\n", entry->fts_name);
-        cpio_append_fts_entry (entry);
+        writer->wr_fts_entry (entry);
       }
     } else
       /* It's some other sort of file, or a directory, always include. */
-      cpio_append_fts_entry (entry);
+      writer->wr_fts_entry (entry);
   }
 
   if (fts_close (fts) == -1)
-    error (EXIT_FAILURE, errno, "write_kernel_modules: fts_close: %s", modpath);
+    error (EXIT_FAILURE, errno, "add_kernel_modules: fts_close: %s", modpath);
 }
 
 /* Copy the host files.
@@ -254,7 +231,7 @@ write_kernel_modules (const char *whitelist_file, const char *modpath)
  * that exist.  Ignore any files that don't exist or are not readable.
  */
 static void
-write_hostfiles (const char *hostfiles_file)
+add_hostfiles (const char *hostfiles_file, struct writer *writer)
 {
   char **hostfiles = load_file (hostfiles_file);
 
@@ -287,7 +264,7 @@ write_hostfiles (const char *hostfiles_file)
         if (verbose >= 2)
           fprintf (stderr, "including host file %s (matches %s)\n", tmp, patt);
 
-        cpio_append (tmp);
+        writer->wr_file (tmp);
 
         free (tmp);
       }
@@ -298,204 +275,7 @@ write_hostfiles (const char *hostfiles_file)
         fprintf (stderr, "including host file %s (directly referenced)\n",
                  hostfile);
 
-      cpio_append_stat (hostfile, &statbuf);
+      writer->wr_file_stat (hostfile, &statbuf);
     } /* Ignore files that don't exist. */
   }
 }
-
-/* Copy contents of buffer to out_fd and keep out_offset correct. */
-static void
-write_to_fd (const void *buffer, size_t len)
-{
-  if (full_write (out_fd, buffer, len) != len)
-    error (EXIT_FAILURE, errno, "write");
-  out_offset += len;
-}
-
-/* Copy contents of file to out_fd. */
-static void
-write_file_to_fd (const char *filename)
-{
-  char buffer[BUFFER_SIZE];
-  int fd2;
-  ssize_t r;
-
-  if (verbose >= 2)
-    fprintf (stderr, "write_file_to_fd %s -> %d\n", filename, out_fd);
-
-  fd2 = open (filename, O_RDONLY);
-  if (fd2 == -1)
-    error (EXIT_FAILURE, errno, "open: %s", filename);
-  for (;;) {
-    r = read (fd2, buffer, sizeof buffer);
-    if (r == 0)
-      break;
-    if (r == -1) {
-      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
-        continue;
-      error (EXIT_FAILURE, errno, "read: %s", filename);
-    }
-    write_to_fd (buffer, r);
-  }
-
-  if (close (fd2) == -1)
-    error (EXIT_FAILURE, errno, "close: %s", filename);
-}
-
-/* Copy file of given length to output, and fail if the file has
- * changed size.
- */
-static void
-write_file_len_to_fd (const char *filename, size_t len)
-{
-  char buffer[BUFFER_SIZE];
-  size_t count = 0;
-
-  if (verbose >= 2)
-    fprintf (stderr, "write_file_to_fd %s -> %d\n", filename, out_fd);
-
-  int fd2 = open (filename, O_RDONLY);
-  if (fd2 == -1)
-    error (EXIT_FAILURE, errno, "open: %s", filename);
-  for (;;) {
-    ssize_t r = read (fd2, buffer, sizeof buffer);
-    if (r == 0)
-      break;
-    if (r == -1) {
-      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
-        continue;
-      error (EXIT_FAILURE, errno, "read: %s", filename);
-    }
-    write_to_fd (buffer, r);
-    count += r;
-    if (count > len)
-      error (EXIT_FAILURE, 0, "write_file_len_to_fd: %s: file has increased in size\n", filename);
-  }
-
-  if (close (fd2) == -1)
-    error (EXIT_FAILURE, errno, "close: %s", filename);
-
-  if (count != len)
-    error (EXIT_FAILURE, 0, "febootstrap-supermin-helper: write_file_len_to_fd: %s: file has changed size\n", filename);
-}
-
-/* Append the file pointed to by FTSENT to the cpio output. */
-static void
-cpio_append_fts_entry (FTSENT *entry)
-{
-  if (entry->fts_info & FTS_NS || entry->fts_info & FTS_NSOK)
-    cpio_append (entry->fts_path);
-  else
-    cpio_append_stat (entry->fts_path, entry->fts_statp);
-}
-
-/* Append the file named 'filename' to the cpio output. */
-static void
-cpio_append (const char *filename)
-{
-  struct stat statbuf;
-
-  if (lstat (filename, &statbuf) == -1)
-    error (EXIT_FAILURE, errno, "lstat: %s", filename);
-  cpio_append_stat (filename, &statbuf);
-}
-
-/* Append the file to the cpio output. */
-#define PADDING(len) ((((len) + 3) & ~3) - (len))
-
-#define CPIO_HEADER_LEN (6 + 13*8)
-
-static void
-cpio_append_stat (const char *filename, struct stat *statbuf)
-{
-  const char *orig_filename = filename;
-
-  if (*filename == '/')
-    filename++;
-  if (*filename == '\0')
-    filename = ".";
-
-  if (verbose >= 2)
-    fprintf (stderr, "cpio_append_stat %s 0%o -> %d\n",
-             orig_filename, statbuf->st_mode, out_fd);
-
-  /* Regular files and symlinks are the only ones that have a "body"
-   * in this cpio entry.
-   */
-  int has_body = S_ISREG (statbuf->st_mode) || S_ISLNK (statbuf->st_mode);
-
-  size_t len = strlen (filename) + 1;
-
-  char header[CPIO_HEADER_LEN + 1];
-  snprintf (header, sizeof header,
-            "070701"            /* magic */
-            "%08X"              /* inode */
-            "%08X"              /* mode */
-            "%08X" "%08X"       /* uid, gid */
-            "%08X"              /* nlink */
-            "%08X"              /* mtime */
-            "%08X"              /* file length */
-            "%08X" "%08X"       /* device holding file major, minor */
-            "%08X" "%08X"       /* for specials, device major, minor */
-            "%08X"              /* name length (including \0 byte) */
-            "%08X",             /* checksum (not used by the kernel) */
-            (unsigned) statbuf->st_ino, statbuf->st_mode,
-            statbuf->st_uid, statbuf->st_gid,
-            (unsigned) statbuf->st_nlink, (unsigned) statbuf->st_mtime,
-            has_body ? (unsigned) statbuf->st_size : 0,
-            major (statbuf->st_dev), minor (statbuf->st_dev),
-            major (statbuf->st_rdev), minor (statbuf->st_rdev),
-            (unsigned) len, 0);
-
-  /* Write the header. */
-  write_to_fd (header, CPIO_HEADER_LEN);
-
-  /* Follow with the filename, and pad it. */
-  write_to_fd (filename, len);
-  size_t padding_len = PADDING (CPIO_HEADER_LEN + len);
-  write_padding (padding_len);
-
-  /* Follow with the file or symlink content, and pad it. */
-  if (has_body) {
-    if (S_ISREG (statbuf->st_mode))
-      write_file_len_to_fd (orig_filename, statbuf->st_size);
-    else if (S_ISLNK (statbuf->st_mode)) {
-      char tmp[PATH_MAX];
-      if (readlink (orig_filename, tmp, sizeof tmp) == -1)
-        error (EXIT_FAILURE, errno, "readlink: %s", orig_filename);
-      write_to_fd (tmp, statbuf->st_size);
-    }
-
-    padding_len = PADDING (statbuf->st_size);
-    write_padding (padding_len);
-  }
-}
-
-/* CPIO voodoo. */
-static void
-cpio_append_trailer (void)
-{
-  struct stat statbuf;
-  memset (&statbuf, 0, sizeof statbuf);
-  statbuf.st_nlink = 1;
-  cpio_append_stat ("TRAILER!!!", &statbuf);
-
-  /* CPIO seems to pad up to the next block boundary, ie. up to
-   * the next 512 bytes.
-   */
-  write_padding (((out_offset + 511) & ~511) - out_offset);
-  assert ((out_offset & 511) == 0);
-}
-
-/* Write 'len' bytes of zeroes out. */
-static void
-write_padding (size_t len)
-{
-  static const char buffer[512] = { 0 };
-
-  while (len > 0) {
-    size_t n = len < sizeof buffer ? len : sizeof buffer;
-    write_to_fd (buffer, n);
-    len -= n;
-  }
-}
diff --git a/helper/cpio.c b/helper/cpio.c
new file mode 100644
index 0000000..f9ffc3f
--- /dev/null
+++ b/helper/cpio.c
@@ -0,0 +1,278 @@
+/* febootstrap-supermin-helper reimplementation in C.
+ * Copyright (C) 2009-2010 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include "error.h"
+#include "fts_.h"
+#include "full-write.h"
+#include "xalloc.h"
+#include "xvasprintf.h"
+
+#include "helper.h"
+
+/* Buffer size used in copy operations throughout.  Large for
+ * greatest efficiency.
+ */
+#define BUFFER_SIZE 65536
+
+static int out_fd = -1;
+static off_t out_offset = 0;
+
+static void write_file_to_fd (const char *filename);
+static void write_file_len_to_fd (const char *filename, size_t len);
+static void write_padding (size_t len);
+static void cpio_append_fts_entry (FTSENT *entry);
+static void cpio_append_stat (const char *filename, const struct stat *);
+static void cpio_append (const char *filename);
+static void cpio_append_trailer (void);
+
+/* Copy contents of buffer to out_fd and keep out_offset correct. */
+static void
+write_to_fd (const void *buffer, size_t len)
+{
+  if (full_write (out_fd, buffer, len) != len)
+    error (EXIT_FAILURE, errno, "write");
+  out_offset += len;
+}
+
+/* Copy contents of file to out_fd. */
+static void
+write_file_to_fd (const char *filename)
+{
+  char buffer[BUFFER_SIZE];
+  int fd2;
+  ssize_t r;
+
+  if (verbose >= 2)
+    fprintf (stderr, "write_file_to_fd %s -> %d\n", filename, out_fd);
+
+  fd2 = open (filename, O_RDONLY);
+  if (fd2 == -1)
+    error (EXIT_FAILURE, errno, "open: %s", filename);
+  for (;;) {
+    r = read (fd2, buffer, sizeof buffer);
+    if (r == 0)
+      break;
+    if (r == -1) {
+      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+        continue;
+      error (EXIT_FAILURE, errno, "read: %s", filename);
+    }
+    write_to_fd (buffer, r);
+  }
+
+  if (close (fd2) == -1)
+    error (EXIT_FAILURE, errno, "close: %s", filename);
+}
+
+/* Copy file of given length to output, and fail if the file has
+ * changed size.
+ */
+static void
+write_file_len_to_fd (const char *filename, size_t len)
+{
+  char buffer[BUFFER_SIZE];
+  size_t count = 0;
+
+  if (verbose >= 2)
+    fprintf (stderr, "write_file_to_fd %s -> %d\n", filename, out_fd);
+
+  int fd2 = open (filename, O_RDONLY);
+  if (fd2 == -1)
+    error (EXIT_FAILURE, errno, "open: %s", filename);
+  for (;;) {
+    ssize_t r = read (fd2, buffer, sizeof buffer);
+    if (r == 0)
+      break;
+    if (r == -1) {
+      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+        continue;
+      error (EXIT_FAILURE, errno, "read: %s", filename);
+    }
+    write_to_fd (buffer, r);
+    count += r;
+    if (count > len)
+      error (EXIT_FAILURE, 0, "write_file_len_to_fd: %s: file has increased in size\n", filename);
+  }
+
+  if (close (fd2) == -1)
+    error (EXIT_FAILURE, errno, "close: %s", filename);
+
+  if (count != len)
+    error (EXIT_FAILURE, 0, "febootstrap-supermin-helper: write_file_len_to_fd: %s: file has changed size\n", filename);
+}
+
+/* Append the file pointed to by FTSENT to the cpio output. */
+static void
+cpio_append_fts_entry (FTSENT *entry)
+{
+  if (entry->fts_info & FTS_NS || entry->fts_info & FTS_NSOK)
+    cpio_append (entry->fts_path);
+  else
+    cpio_append_stat (entry->fts_path, entry->fts_statp);
+}
+
+/* Append the file named 'filename' to the cpio output. */
+static void
+cpio_append (const char *filename)
+{
+  struct stat statbuf;
+
+  if (lstat (filename, &statbuf) == -1)
+    error (EXIT_FAILURE, errno, "lstat: %s", filename);
+  cpio_append_stat (filename, &statbuf);
+}
+
+/* Append the file to the cpio output. */
+#define PADDING(len) ((((len) + 3) & ~3) - (len))
+
+#define CPIO_HEADER_LEN (6 + 13*8)
+
+static void
+cpio_append_stat (const char *filename, const struct stat *statbuf)
+{
+  const char *orig_filename = filename;
+
+  if (*filename == '/')
+    filename++;
+  if (*filename == '\0')
+    filename = ".";
+
+  if (verbose >= 2)
+    fprintf (stderr, "cpio_append_stat %s 0%o -> %d\n",
+             orig_filename, statbuf->st_mode, out_fd);
+
+  /* Regular files and symlinks are the only ones that have a "body"
+   * in this cpio entry.
+   */
+  int has_body = S_ISREG (statbuf->st_mode) || S_ISLNK (statbuf->st_mode);
+
+  size_t len = strlen (filename) + 1;
+
+  char header[CPIO_HEADER_LEN + 1];
+  snprintf (header, sizeof header,
+            "070701"            /* magic */
+            "%08X"              /* inode */
+            "%08X"              /* mode */
+            "%08X" "%08X"       /* uid, gid */
+            "%08X"              /* nlink */
+            "%08X"              /* mtime */
+            "%08X"              /* file length */
+            "%08X" "%08X"       /* device holding file major, minor */
+            "%08X" "%08X"       /* for specials, device major, minor */
+            "%08X"              /* name length (including \0 byte) */
+            "%08X",             /* checksum (not used by the kernel) */
+            (unsigned) statbuf->st_ino, statbuf->st_mode,
+            statbuf->st_uid, statbuf->st_gid,
+            (unsigned) statbuf->st_nlink, (unsigned) statbuf->st_mtime,
+            has_body ? (unsigned) statbuf->st_size : 0,
+            major (statbuf->st_dev), minor (statbuf->st_dev),
+            major (statbuf->st_rdev), minor (statbuf->st_rdev),
+            (unsigned) len, 0);
+
+  /* Write the header. */
+  write_to_fd (header, CPIO_HEADER_LEN);
+
+  /* Follow with the filename, and pad it. */
+  write_to_fd (filename, len);
+  size_t padding_len = PADDING (CPIO_HEADER_LEN + len);
+  write_padding (padding_len);
+
+  /* Follow with the file or symlink content, and pad it. */
+  if (has_body) {
+    if (S_ISREG (statbuf->st_mode))
+      write_file_len_to_fd (orig_filename, statbuf->st_size);
+    else if (S_ISLNK (statbuf->st_mode)) {
+      char tmp[PATH_MAX];
+      if (readlink (orig_filename, tmp, sizeof tmp) == -1)
+        error (EXIT_FAILURE, errno, "readlink: %s", orig_filename);
+      write_to_fd (tmp, statbuf->st_size);
+    }
+
+    padding_len = PADDING (statbuf->st_size);
+    write_padding (padding_len);
+  }
+}
+
+/* CPIO voodoo. */
+static void
+cpio_append_trailer (void)
+{
+  struct stat statbuf;
+  memset (&statbuf, 0, sizeof statbuf);
+  statbuf.st_nlink = 1;
+  cpio_append_stat ("TRAILER!!!", &statbuf);
+
+  /* CPIO seems to pad up to the next block boundary, ie. up to
+   * the next 512 bytes.
+   */
+  write_padding (((out_offset + 511) & ~511) - out_offset);
+  assert ((out_offset & 511) == 0);
+}
+
+/* Write 'len' bytes of zeroes out. */
+static void
+write_padding (size_t len)
+{
+  static const char buffer[512] = { 0 };
+
+  while (len > 0) {
+    size_t n = len < sizeof buffer ? len : sizeof buffer;
+    write_to_fd (buffer, n);
+    len -= n;
+  }
+}
+
+static void
+cpio_start (const char *appliance)
+{
+  out_fd = open (appliance, O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY, 0644);
+  if (out_fd == -1)
+    error (EXIT_FAILURE, errno, "open: %s", appliance);
+  out_offset = 0;
+}
+
+static void
+cpio_end (void)
+{
+  cpio_append_trailer ();
+
+  /* Finish off and close output file. */
+  if (close (out_fd) == -1)
+    error (EXIT_FAILURE, errno, "close");
+}
+
+struct writer cpio_writer = {
+  .wr_start = cpio_start,
+  .wr_end = cpio_end,
+  .wr_file = cpio_append,
+  .wr_file_stat = cpio_append_stat,
+  .wr_fts_entry = cpio_append_fts_entry,
+  .wr_cpio_file = write_file_to_fd,
+};
diff --git a/helper/helper.h b/helper/helper.h
index e9618ba..75b6eb3 100644
--- a/helper/helper.h
+++ b/helper/helper.h
@@ -19,12 +19,36 @@
 #ifndef FEBOOTSTRAP_SUPERMIN_HELPER_H
 #define FEBOOTSTRAP_SUPERMIN_HELPER_H
 
+#include <sys/stat.h>
+#include "fts_.h"
+
+struct writer {
+  /* Start a new appliance, finish one off. */
+  void (*wr_start) (const char *appliance);
+  void (*wr_end) (void);
+
+  /* Append the named host file to the appliance being built.  The
+   * wr_file_stat form is used where we have already stat'd this file,
+   * to avoid having to stat it a second time.  The wr_fts_entry form
+   * is used where the caller has an FTSENT.
+   */
+  void (*wr_file) (const char *filename);
+  void (*wr_file_stat) (const char *filename, const struct stat *);
+  void (*wr_fts_entry) (FTSENT *entry);
+
+  /* Append the contents of cpio file to the appliance being built. */
+  void (*wr_cpio_file) (const char *cpio_file);
+};
+
 /* main.c */
 extern struct timeval start_t;
 extern int verbose;
 
 /* appliance.c */
-extern void create_appliance (char **inputs, int nr_inputs, const char *whitelist, const char *modpath, const char *appliance);
+extern void create_appliance (char **inputs, int nr_inputs, const char *whitelist, const char *modpath, const char *appliance, struct writer *writer);
+
+/* cpio.c */
+extern struct writer cpio_writer;
 
 /* kernel.c */
 extern const char *create_kernel (const char *hostcpu, const char *kernel);
diff --git a/helper/main.c b/helper/main.c
index d350b4e..a448b9e 100644
--- a/helper/main.c
+++ b/helper/main.c
@@ -152,7 +152,8 @@ main (int argc, char *argv[])
     print_timestamped_message ("finished creating kernel");
 
   /* Create the appliance. */
-  create_appliance (inputs, nr_inputs, whitelist, modpath, appliance);
+  create_appliance (inputs, nr_inputs, whitelist, modpath, appliance,
+                    &cpio_writer);
 
   if (verbose)
     print_timestamped_message ("finished creating appliance");
-- 
1.7.1



More information about the Libguestfs mailing list