first rev of some stupid code for reading/writing cpio archives master origin
authorRex Feany <rfeany@rf.cx>
Tue, 15 Aug 2006 09:39:03 +0000 (09:39 +0000)
committerRex Feany <rfeany@rf.cx>
Tue, 15 Aug 2006 09:39:03 +0000 (09:39 +0000)
cpio-fmt.h [new file with mode: 0644]
creator.c [new file with mode: 0644]
makefile [new file with mode: 0644]
reader.c [new file with mode: 0644]

diff --git a/cpio-fmt.h b/cpio-fmt.h
new file mode 100644 (file)
index 0000000..c8dad27
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef CPIO_FMT_H
+#define CPIO_FMT_H
+
+#define CPIO_MAGIC "070701"
+
+struct cpio_hdr {
+    char    c_magic[6];
+    char    c_ino[8];
+    char    c_mode[8];
+    char    c_uid[8];
+    char    c_gid[8];
+    char    c_nlink[8];
+    char    c_mtime[8];
+    char    c_filesize[8];
+    char    c_devmajor[8];
+    char    c_devminor[8];
+    char    c_rdevmajor[8];
+    char    c_rdevminor[8];
+    char    c_namesize[8];
+    char    c_checksum[8];
+};
+
+static int pad(int size)
+{
+    int tail = size % 4;
+
+    if (tail)
+       size = size + (4 - tail);
+    return size;
+}
+
+
+#endif /* CPIO_FMT_H */
diff --git a/creator.c b/creator.c
new file mode 100644 (file)
index 0000000..542d697
--- /dev/null
+++ b/creator.c
@@ -0,0 +1,184 @@
+#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;
+}
diff --git a/makefile b/makefile
new file mode 100644 (file)
index 0000000..895ae82
--- /dev/null
+++ b/makefile
@@ -0,0 +1,29 @@
+CFLAGS = -Wall -Werror -O6 -MMD
+
+SRCS = reader.c creator.c
+
+
+all: cpio-lister cpio-creator
+       
+cpio-lister: reader.o
+       $(CC) -o $@ $^
+
+cpio-creator: creator.o
+       $(CC) -o $@ $^
+
+clean:
+       rm -f $(SRCS:.c=.o) $(SRCS:.c=.d) cpio-lister cpio-creator
+
+
+
+-include $(SRCS:.c=.d)
+
+
+
+
+
+
+
+
+
+
diff --git a/reader.c b/reader.c
new file mode 100644 (file)
index 0000000..5aae302
--- /dev/null
+++ b/reader.c
@@ -0,0 +1,140 @@
+#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;
+}