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