first rev of some stupid code for reading/writing cpio archives
[rcpio.git] / creator.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <sys/mman.h>
4 #include <ctype.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <sys/types.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 #include <string.h>
12 #include <assert.h>
13
14 #include "cpio-fmt.h"
15
16 static void write_cpio_record(const char *ptr, const char *data, struct stat *st)
17 {
18     struct cpio_hdr *hdr;
19     char *cpio_rec;
20     int data_start;
21     int size;
22
23     data_start = size = pad(sizeof(*hdr) + strlen(ptr) + 1);
24     if (data)
25         size += pad(strlen(data)+1);
26
27     hdr = malloc(size);
28     cpio_rec = (char *)hdr; 
29     memset(hdr, 0, size);
30
31     sprintf(hdr->c_magic, "%6.6s", CPIO_MAGIC);
32     sprintf(hdr->c_ino, "%8.8x", 0);
33     sprintf(hdr->c_mode, "%8.8x", st->st_mode);
34     sprintf(hdr->c_uid, "%8.8x", 0);
35     sprintf(hdr->c_gid, "%8.8x", 0);
36     sprintf(hdr->c_nlink, "%8.8x", 0);
37     sprintf(hdr->c_mtime, "%8.8x", 0);
38     sprintf(hdr->c_filesize, "%8.8x", data ? strlen(data)+1 : 0);
39     sprintf(hdr->c_devmajor, "%8.8x", 0);
40     sprintf(hdr->c_devminor, "%8.8x", 0);
41     sprintf(hdr->c_rdevmajor, "%8.8x", major(st->st_rdev));
42     sprintf(hdr->c_rdevminor, "%8.8x", minor(st->st_rdev));
43     sprintf(hdr->c_namesize, "%8.8x", strlen(ptr)+1);
44     sprintf(hdr->c_checksum, "%8.8x", 0);
45     memcpy(hdr+1, ptr, strlen(ptr));
46     if (data)
47         memcpy(cpio_rec+data_start, data, strlen(data));
48
49     fprintf(stderr, "got size %d\n", size);
50     fflush(stdout);
51     write(STDOUT_FILENO, cpio_rec, size);
52 }
53
54 static int parse_rwx(char thing)
55 {
56     switch (thing) {
57         case 'r': return 4;
58         case 'w': return 2;
59         case 'x': return 1;
60         case '-': return 0;
61     }
62     abort();
63 }
64
65 static int parse_rwx_group(char **data, int mult)
66 {
67     char *ptr = *data;
68     int x = parse_rwx(*ptr++) + parse_rwx(*ptr++) + parse_rwx(*ptr++);
69     *data = ptr;
70     return x * mult;
71 }
72
73 static int parse_mode(char **data, unsigned int *mode)
74 {
75     char *ptr = *data;
76
77     switch (*ptr) {
78         case 'c':
79             *mode |= S_IFCHR; break;
80         case 'l':
81             *mode |= S_IFLNK; break;
82         case 'd':
83             *mode |= S_IFDIR; break;
84         case 'b':
85             *mode |= S_IFBLK; break;
86         case '-':
87             *mode |= S_IFREG; break;
88         default:
89             fprintf(stderr, "unknown mode %c\n", *ptr);
90             exit(1);
91     }
92     *data = ++ptr;
93     *mode |= (parse_rwx_group(data, 8*8) + parse_rwx_group(data, 8) + parse_rwx_group(data, 1));
94     return 0;
95 }
96
97 void parse_major_minor(char **data, struct stat *st)
98 {
99     char *ptr = *data, *end;
100     int maj, min;
101
102     if (S_ISDIR(st->st_mode)) {
103         goto out;
104     } else if (S_ISLNK(st->st_mode)) {
105         strtoul(ptr, &end, 10);
106         ptr = end;
107         goto out;
108     }
109
110     maj = strtoul(ptr, &end, 10);
111     assert(*end == ',');
112     assert(maj);
113
114     ptr = end+1;
115     min = strtoul(ptr, &end, 10);
116     assert(*end == ' ');
117
118     st->st_rdev = makedev(maj, min);
119     assert(*end == ' ');
120     ptr = end;
121
122 out:
123     while (*ptr == ' ') 
124         ++ptr;
125     *data = ptr;
126 }
127
128 /** chomp whitespace from the end of the string */
129 int chomp(char *str)
130 {
131     int len=strlen(str);
132     while ((len > 0) && isspace(str[len-1]))
133         str[--len] = '\0';
134     return len;
135 }
136
137
138 static void parse_link_name(char *ptr, char **data)
139 {
140     char *arrow = strstr(ptr, " -> ");
141
142     if (!arrow)
143         abort();
144
145     *arrow = '\0';
146     *data = arrow+4;
147     fprintf(stderr, "got name '%s' and link '%s'\n", ptr, *data);
148 }
149
150
151 int main(int argc, char **argv) {
152     char buf[BUFSIZ];
153     struct stat st;
154
155     if (argc != 1) {
156         fprintf(stderr, "%s\n", argv[0]);
157         exit(1);
158     }
159
160     while ((fgets(buf, sizeof(buf), stdin))) {
161         char *ptr = buf;
162         char *data = NULL;
163
164         chomp(ptr);
165         memset(&st, 0, sizeof(st));
166         fprintf(stderr, "\ngot line '%s'\n", buf);
167
168         parse_mode(&ptr, &st.st_mode);
169         fprintf(stderr, "got st_mode %o\n", st.st_mode);
170         assert(*ptr == ' ');
171
172         parse_major_minor(&ptr, &st);
173         fprintf(stderr, "got maj %d min %d\n", major(st.st_rdev), minor(st.st_rdev));
174         fprintf(stderr, "got name '%s'\n", ptr);
175
176         if (S_ISLNK(st.st_mode))
177             parse_link_name(ptr, &data);
178         write_cpio_record(ptr, data, &st);
179
180     }
181     memset(&st, 0, sizeof(st));
182     write_cpio_record("TRAILER!!!", NULL, &st);
183     return 0;
184 }