|
|
1.1 root 1: //
2: // Stuff to deal with cpio-format files
3: //
4:
5: #include <stdio.h>
6: #include <unistd.h>
7: #include <stdlib.h>
8: #include <fcntl.h>
9: #include <dirent.h>
10: #include <limits.h>
11: #include <sys/stat.h>
12: #include <string.h>
13:
14: #include "cpio.h"
15: #include "buf.h"
16: #include "psxarc.h"
17: #include "links.h"
18:
19: extern int errno;
20: extern int fVerbose;
21:
22: static void cpio_dodir(PBUF pb, char *pchfile, struct stat *psb);
23:
24: //
25: // Convert string pch of length len from octal and return the value.
26: //
27: static int
28: cpio_atoi(char *pch, int len)
29: {
30: int num = 0, i;
31:
32: for (i = 0; i < len; ++i) {
33: num = num * 8 + (pch[i] - '0');
34: }
35: return num;
36: }
37:
38: void
39: CpioList(PBUF pb)
40: {
41: int nbytes;
42: int namesize, filesize;
43: int i;
44: static char pathname[PATH_MAX + NAME_MAX + 2];
45: CPIO_HEAD x;
46:
47: for (;;) {
48: //
49: // read the cpio header
50: //
51:
52: for (i = 0; i < sizeof(x); ++i) {
53: ((char *)&x)[i] = bgetc(pb);
54: }
55: if (0 != strncmp(x.c_magic, MAGIC, strlen(MAGIC))) {
56: fprintf(stderr,
57: "%s: this doesn't look like a cpio archive\n",
58: progname);
59: exit(1);
60: }
61:
62: namesize = cpio_atoi(x.c_namesize, sizeof(x.c_namesize));
63: filesize = cpio_atoi(x.c_filesize, sizeof(x.c_filesize));
64:
65: for (i = 0; i < namesize; ++i) {
66: // nb: namesize includes the null
67: pathname[i] = bgetc(pb);
68: }
69: if (0 == strcmp(pathname, LASTFILENAME)) {
70: break;
71: }
72:
73: printf("%s\n", pathname);
74:
75: // skip the file data
76: for (i = 0; i < filesize; ++i) {
77: (void)bgetc(pb);
78: }
79: }
80: }
81:
82: void
83: CpioRead(PBUF pb)
84: {
85: int fdout;
86: int mode;
87: int i;
88: int namesize, filesize;
89: static CPIO_HEAD x;
90: static char pathname[PATH_MAX + NAME_MAX + 2];
91:
92: for (;;) {
93: //
94: // read the cpio header
95: //
96:
97: for (i = 0; i < sizeof(x); ++i) {
98: ((char *)&x)[i] = bgetc(pb);
99: }
100:
101: if (0 != strncmp(x.c_magic, MAGIC, strlen(MAGIC))) {
102: fprintf(stderr,
103: "%s: this doesn't look like a cpio archive\n",
104: progname);
105: exit(1);
106: }
107:
108: namesize = cpio_atoi(x.c_namesize, sizeof(x.c_namesize));
109: filesize = cpio_atoi(x.c_filesize, sizeof(x.c_filesize));
110:
111: for (i = 0; i < namesize; ++i) {
112: // nb: namesize includes the null
113: pathname[i] = bgetc(pb);
114: }
115: if (0 == strcmp(pathname, LASTFILENAME)) {
116: break;
117: }
118:
119: if (fVerbose) {
120: printf("%s\n", pathname);
121: }
122:
123: mode = cpio_atoi(x.c_mode, sizeof(x.c_mode));
124:
125: if (mode & C_ISDIR) {
126: mkdir(pathname, 0777);
127: } else if (mode & C_ISFIFO) {
128: mkfifo(pathname, 0666);
129: } else if (mode & C_ISREG) {
130: fdout = open(pathname, O_WRONLY | O_CREAT, 0666);
131: if (-1 == fdout) {
132: fprintf(stderr, "%s: open: ", progname);
133: perror(pathname);
134:
135: // we could continue, but we'd have to be sure
136: // to skip this file's data.
137:
138: exit(1);
139: }
140: for (i = 0; i < filesize; ++i) {
141: char c;
142: c = (char)bgetc(pb);
143: (void)write(fdout, &c, 1);
144: --filesize;
145: }
146: (void)close(fdout);
147: } else if (mode & C_ISLNK) {
148: // XXX.mjb: symbolic link
149: } else {
150: fprintf(stderr, "%s: unknown mode 0%o\n", progname, mode);
151: exit(4);
152: }
153: }
154: }
155:
156: void
157: cpio_itoa(int i, char *pch, int len)
158: {
159: int j;
160: char buf[20];
161:
162: sprintf(buf, "%o", i);
163:
164: j = strlen(buf);
165: if (j > len) {
166: printf("itoa: not enough room in buf: need %d, have %d\n",
167: j, len);
168: exit(3);
169: }
170:
171: memset(pch, '0', len);
172: strncpy(&pch[len - j], buf, strlen(buf));
173: }
174:
175: void
176: CpioWrite(PBUF pb, char **files, int count)
177: {
178: CPIO_HEAD h;
179: struct stat statbuf;
180: int i, len;
181: int fdin;
182:
183: (void)strncpy(h.c_magic, MAGIC, strlen(MAGIC));
184:
185: while (count > 0) {
186: if (fVerbose) {
187: printf("%s\n", *files);
188: }
189: if (-1 == (fdin = open(*files, O_RDONLY))) {
190: fprintf(stderr, "%s: open: ");
191: perror(*files);
192: exit(1);
193: }
194: if (-1 == fstat(fdin, &statbuf)) {
195: perror("fstat");
196: exit(1);
197: }
198:
199: cpio_itoa(strlen(*files) + 1, h.c_namesize, sizeof(h.c_namesize));
200: cpio_itoa(statbuf.st_dev, h.c_dev, sizeof(h.c_dev));
201: cpio_itoa(statbuf.st_ino, h.c_ino, sizeof(h.c_ino));
202: cpio_itoa(statbuf.st_uid, h.c_uid, sizeof(h.c_uid));
203: cpio_itoa(statbuf.st_gid, h.c_gid, sizeof(h.c_gid));
204: cpio_itoa(statbuf.st_nlink, h.c_nlink, sizeof(h.c_nlink));
205: cpio_itoa(statbuf.st_mtime, h.c_mtime, sizeof(h.c_mtime));
206:
207: if (S_ISDIR(statbuf.st_mode)) {
208: cpio_itoa(C_ISDIR, h.c_mode, sizeof(h.c_mode));
209: cpio_itoa(0, h.c_filesize, sizeof(h.c_filesize));
210:
211: // write the header
212:
213: for (i = 0; i < sizeof(h); ++i) {
214: bputc(pb, ((char *)&h)[i]);
215: }
216:
217: // write the directory name
218:
219: len = strlen(*files) + 1; // the nul, too
220: for (i = 0; i < len; ++i) {
221: bputc(pb, (*files)[i]);
222: }
223:
224: // write the directory contents
225: cpio_dodir(pb, *files, &statbuf);
226:
227: count--;
228: files++;
229: continue;
230: }
231: if (S_ISFIFO(statbuf.st_mode)) {
232: cpio_itoa(C_ISFIFO, h.c_mode, sizeof(h.c_mode));
233: cpio_itoa(0, h.c_filesize, sizeof(h.c_filesize));
234: } else if (S_ISREG(statbuf.st_mode)) {
235: cpio_itoa(C_ISREG, h.c_mode, sizeof(h.c_mode));
236: cpio_itoa(statbuf.st_size, h.c_filesize, sizeof(h.c_filesize));
237: } else {
238: printf("I'm not prepared to deal with the file type "
239: "of %s\n", *files);
240: exit(2);
241: }
242:
243: // write the cpio header
244: for (i = 0; i < sizeof(h); ++i) {
245: bputc(pb, ((char *)&h)[i]);
246: }
247:
248: // write the filename
249:
250: len = strlen(*files) + 1; // the nul, too
251: for (i = 0; i < len; ++i) {
252: bputc(pb, (*files)[i]);
253: }
254:
255: while (statbuf.st_size > 0) {
256: char b;
257: (void)read(fdin, &b, 1);
258: bputc(pb, b);
259: --statbuf.st_size;
260: }
261:
262: close(fdin);
263: count--;
264: files++;
265: }
266:
267: #if 0
268: printf("", count); // null function call to work around
269: // mips code generator problem
270: #endif
271: }
272:
273: static void
274: cpio_dodir(PBUF pb, char *pchfile, struct stat *psb)
275: {
276: DIR *dp;
277: struct dirent *dirent;
278: char *pch;
279:
280: dp = opendir(pchfile);
281: if (NULL == dp) {
282: fprintf(stderr, "%s: opendir: ", progname);
283: perror(pchfile);
284: return;
285: }
286: while (NULL != (dirent = readdir(dp))) {
287: if ('.' == dirent->d_name[0] &&
288: ('\0' == dirent->d_name[1] ||
289: 0 == strcmp(dirent->d_name, ".."))) {
290: continue;
291: }
292:
293: //
294: // Recurse. We append the file name read from the directory
295: // to the directory name we were given and call CpioWrite to
296: // put it on the tape. It could be a directory, so we could
297: // end up back here. This means that we must allocate the
298: // space for the pathname dynamically. This seems like it
299: // will be a big time-waster.
300: //
301:
302: // strlen + 2: one extra for '/', one extra for nul.
303: pch = malloc(strlen(pchfile) + strlen(dirent->d_name) + 2);
304: if (NULL == pch) {
305: fprintf(stderr, "%s: virtual memory exhausted\n",
306: progname);
307: exit(4);
308: }
309: strcpy(pch, pchfile);
310: strcat(pch, "/");
311: strcat(pch, dirent->d_name);
312:
313: CpioWrite(pb, &pch, 1);
314:
315: free(pch);
316: }
317: (void)closedir(dp);
318: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.