--- /dev/null
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/mman.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <assert.h>
+
+#include "cpio-fmt.h"
+
+static void write_cpio_record(const char *ptr, const char *data, struct stat *st)
+{
+ struct cpio_hdr *hdr;
+ char *cpio_rec;
+ int data_start;
+ int size;
+
+ data_start = size = pad(sizeof(*hdr) + strlen(ptr) + 1);
+ if (data)
+ size += pad(strlen(data)+1);
+
+ hdr = malloc(size);
+ cpio_rec = (char *)hdr;
+ memset(hdr, 0, size);
+
+ sprintf(hdr->c_magic, "%6.6s", CPIO_MAGIC);
+ sprintf(hdr->c_ino, "%8.8x", 0);
+ sprintf(hdr->c_mode, "%8.8x", st->st_mode);
+ sprintf(hdr->c_uid, "%8.8x", 0);
+ sprintf(hdr->c_gid, "%8.8x", 0);
+ sprintf(hdr->c_nlink, "%8.8x", 0);
+ sprintf(hdr->c_mtime, "%8.8x", 0);
+ sprintf(hdr->c_filesize, "%8.8x", data ? strlen(data)+1 : 0);
+ sprintf(hdr->c_devmajor, "%8.8x", 0);
+ sprintf(hdr->c_devminor, "%8.8x", 0);
+ sprintf(hdr->c_rdevmajor, "%8.8x", major(st->st_rdev));
+ sprintf(hdr->c_rdevminor, "%8.8x", minor(st->st_rdev));
+ sprintf(hdr->c_namesize, "%8.8x", strlen(ptr)+1);
+ sprintf(hdr->c_checksum, "%8.8x", 0);
+ memcpy(hdr+1, ptr, strlen(ptr));
+ if (data)
+ memcpy(cpio_rec+data_start, data, strlen(data));
+
+ fprintf(stderr, "got size %d\n", size);
+ fflush(stdout);
+ write(STDOUT_FILENO, cpio_rec, size);
+}
+
+static int parse_rwx(char thing)
+{
+ switch (thing) {
+ case 'r': return 4;
+ case 'w': return 2;
+ case 'x': return 1;
+ case '-': return 0;
+ }
+ abort();
+}
+
+static int parse_rwx_group(char **data, int mult)
+{
+ char *ptr = *data;
+ int x = parse_rwx(*ptr++) + parse_rwx(*ptr++) + parse_rwx(*ptr++);
+ *data = ptr;
+ return x * mult;
+}
+
+static int parse_mode(char **data, unsigned int *mode)
+{
+ char *ptr = *data;
+
+ switch (*ptr) {
+ case 'c':
+ *mode |= S_IFCHR; break;
+ case 'l':
+ *mode |= S_IFLNK; break;
+ case 'd':
+ *mode |= S_IFDIR; break;
+ case 'b':
+ *mode |= S_IFBLK; break;
+ case '-':
+ *mode |= S_IFREG; break;
+ default:
+ fprintf(stderr, "unknown mode %c\n", *ptr);
+ exit(1);
+ }
+ *data = ++ptr;
+ *mode |= (parse_rwx_group(data, 8*8) + parse_rwx_group(data, 8) + parse_rwx_group(data, 1));
+ return 0;
+}
+
+void parse_major_minor(char **data, struct stat *st)
+{
+ char *ptr = *data, *end;
+ int maj, min;
+
+ if (S_ISDIR(st->st_mode)) {
+ goto out;
+ } else if (S_ISLNK(st->st_mode)) {
+ strtoul(ptr, &end, 10);
+ ptr = end;
+ goto out;
+ }
+
+ maj = strtoul(ptr, &end, 10);
+ assert(*end == ',');
+ assert(maj);
+
+ ptr = end+1;
+ min = strtoul(ptr, &end, 10);
+ assert(*end == ' ');
+
+ st->st_rdev = makedev(maj, min);
+ assert(*end == ' ');
+ ptr = end;
+
+out:
+ while (*ptr == ' ')
+ ++ptr;
+ *data = ptr;
+}
+
+/** chomp whitespace from the end of the string */
+int chomp(char *str)
+{
+ int len=strlen(str);
+ while ((len > 0) && isspace(str[len-1]))
+ str[--len] = '\0';
+ return len;
+}
+
+
+static void parse_link_name(char *ptr, char **data)
+{
+ char *arrow = strstr(ptr, " -> ");
+
+ if (!arrow)
+ abort();
+
+ *arrow = '\0';
+ *data = arrow+4;
+ fprintf(stderr, "got name '%s' and link '%s'\n", ptr, *data);
+}
+
+
+int main(int argc, char **argv) {
+ char buf[BUFSIZ];
+ struct stat st;
+
+ if (argc != 1) {
+ fprintf(stderr, "%s\n", argv[0]);
+ exit(1);
+ }
+
+ while ((fgets(buf, sizeof(buf), stdin))) {
+ char *ptr = buf;
+ char *data = NULL;
+
+ chomp(ptr);
+ memset(&st, 0, sizeof(st));
+ fprintf(stderr, "\ngot line '%s'\n", buf);
+
+ parse_mode(&ptr, &st.st_mode);
+ fprintf(stderr, "got st_mode %o\n", st.st_mode);
+ assert(*ptr == ' ');
+
+ parse_major_minor(&ptr, &st);
+ fprintf(stderr, "got maj %d min %d\n", major(st.st_rdev), minor(st.st_rdev));
+ fprintf(stderr, "got name '%s'\n", ptr);
+
+ if (S_ISLNK(st.st_mode))
+ parse_link_name(ptr, &data);
+ write_cpio_record(ptr, data, &st);
+
+ }
+ memset(&st, 0, sizeof(st));
+ write_cpio_record("TRAILER!!!", NULL, &st);
+ return 0;
+}
--- /dev/null
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <sys/mman.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "cpio-fmt.h"
+
+static int extract_num(const char *num, int len)
+{
+ char buffer[len];
+
+ memcpy(buffer, num, len);
+ buffer[len] = '\0';
+
+ return strtoul(buffer, NULL, 16);
+}
+
+static void printf_header(const struct cpio_hdr *hdr)
+{
+ printf(" c_magic %6.6s c_ino %8.8s c_mode %8.8o c_uid %8.8s c_gid %8.8s\n",
+ hdr->c_magic,
+ hdr->c_ino,
+ extract_num(hdr->c_mode, 8),
+ hdr->c_uid,
+ hdr->c_gid);
+
+ printf(" c_nlink %8.8s c_mtime %8.8s c_filesize %8.8s c_namesize %8.8s c_checksum %8.8s\n",
+ hdr->c_nlink,
+ hdr->c_mtime,
+ hdr->c_filesize,
+ hdr->c_namesize,
+ hdr->c_checksum);
+
+ printf("c_devmajor %8.8s c_devminor %8.8s c_rdevmajor %8.8s c_rdevminor %8.8s\n",
+ hdr->c_devmajor,
+ hdr->c_devminor,
+ hdr->c_rdevmajor,
+ hdr->c_rdevminor);
+}
+
+
+static void printf_stat(const struct stat *st)
+{
+ printf("st_ino %lx st_mode %o st_uid %x st_gid %x\n",
+ st->st_ino, st->st_mode, st->st_uid, st->st_gid);
+
+ printf("st_nlink %x\n", st->st_nlink);
+ printf("major %x minor %x\n", major(st->st_rdev), minor(st->st_rdev));
+#if 0
+ dev_t st_dev; /* ID of device containing file */
+ ino_t st_ino; /* inode number */
+ mode_t st_mode; /* protection */
+ nlink_t st_nlink; /* number of hard links */
+ uid_t st_uid; /* user ID of owner */
+ gid_t st_gid; /* group ID of owner */
+ dev_t st_rdev; /* device ID (if special file) */
+ off_t st_size; /* total size, in bytes */
+ blksize_t st_blksize; /* blocksize for filesystem I/O */
+ blkcnt_t st_blocks; /* number of blocks allocated */
+ time_t st_atime; /* time of last access */
+ time_t st_mtime; /* time of last modification */
+ time_t st_ctime; /* time of last status change */
+#endif
+}
+
+static void * print_record(void *ptr)
+{
+ struct stat st;
+ struct cpio_hdr *h = ptr;
+ int namesize, filesize;
+ char *str = (char *)(h + 1);
+
+ if (memcmp(CPIO_MAGIC, h->c_magic, sizeof(CPIO_MAGIC)-1) != 0) {
+ printf("bad magic\n");
+ exit(1);
+ }
+
+ namesize = extract_num(h->c_namesize, 8);
+ filesize = extract_num(h->c_filesize, 8);
+
+ printf("**** [%*.*s] ****************************************************\n", namesize-1, namesize-1, str);
+ printf_header(ptr);
+
+ printf("\n");
+ if (stat(str, &st) >= 0) {
+ printf_stat(&st);
+ }
+ printf("\n");
+
+ return ptr + pad(namesize + sizeof(struct cpio_hdr)) + pad(filesize);
+}
+
+static void print_files(void *ptr, int len)
+{
+ void *end = ptr + len;
+ while ((ptr = print_record(ptr))) {
+ if (ptr >= end)
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct stat st;
+ void *ptr;
+ int fd;
+
+ if (argc != 2) {
+ printf("%s <file>\n", argv[0]);
+ exit(1);
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (fstat(fd, &st) < 0) {
+ perror("stat");
+ exit(1);
+ }
+
+ ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+ print_files(ptr, st.st_size);
+ munmap(ptr, st.st_size);
+ return 0;
+}