From: Rex Feany Date: Tue, 15 Aug 2006 09:39:03 +0000 (+0000) Subject: first rev of some stupid code for reading/writing cpio archives X-Git-Url: https://git.rexfeany.com/?p=rcpio.git;a=commitdiff_plain first rev of some stupid code for reading/writing cpio archives --- diff --git a/cpio-fmt.h b/cpio-fmt.h new file mode 100644 index 0000000..c8dad27 --- /dev/null +++ b/cpio-fmt.h @@ -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 index 0000000..542d697 --- /dev/null +++ b/creator.c @@ -0,0 +1,184 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 index 0000000..5aae302 --- /dev/null +++ b/reader.c @@ -0,0 +1,140 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 \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; +}