|
|
1.1 root 1: #include "asd.h"
2: #include <string.h>
3: #include <time.h>
4: #include <unistd.h>
5: #include "ftw.h"
6:
7: FILE *tf;
8: static Sig_typ sigsav;
9: static int rc;
10: static char tfname[L_tmpnam];
11: static struct stat outsb;
12: static struct pack *pkhead, *pktail;
13:
14: /*
15: * The following structure helps keep track of things being packaged.
16: * iname is the internal name of the component -- in other words,
17: * the archive element name. ename is the (short) pathname of the
18: * file. The structures are chained by the "link" field. All the
19: * other fields are copies of things returned by "stat" and are
20: * used mostly to make sure nothing changed while we were packaging.
21: * head and tail point to the first and last items in the chain.
22: * The first item is known to refer to the "Instructions" component.
23: */
24: struct pack {
25: char *iname;
26: char *ename;
27: struct pack *link;
28: dev_t dev;
29: ino_t ino;
30: int uid, gid, mode;
31: time_t time;
32: off_t size;
33: };
34:
35: /*
36: * Prepare to build a package. The package will appear on stdout.
37: * The argument is nonzero if remarks are to be read.
38: */
39:
40: static void
41: delete(int arg)
42: {
43: unlink (tfname);
44: exit (3);
45: }
46:
47: void
48: pkgstart(void)
49: {
50: struct stat pks;
51:
52: rc = 0;
53:
54: nchk (fstat (fileno (stdout), &outsb));
55:
56: /* establish a temporary file to hold the instruction information */
57: tmpnam (tfname);
58: tf = fopen (tfname, "w");
59: sigsav = signal (SIGINT, SIG_IGN);
60: if (sigsav != SIG_IGN)
61: signal (SIGINT, delete);
62: nchk (chmod (tfname, 0644));
63: schk ((char *) tf);
64:
65: /* create the initial element in the component chain */
66: pkhead = pktail = new (struct pack);
67: pkhead->iname = copy (instr);
68: pkhead->ename = copy (tfname);
69: pkhead->time = 0;
70: pkhead->link = NULL;
71: pkhead->uid = getuid();
72: nchk (fstat (fileno(tf), &pks));
73: pkhead->gid = pks.st_gid;
74: pkhead->mode = 0100644;
75: }
76:
77: static int consider(char *, struct stat *, int, struct FTW *);
78:
79: /*
80: * put a file (or directory) into a package
81: */
82: void
83: pkgfile (char *file)
84: {
85: register int x;
86: struct stat sb;
87:
88: /* if the file is truly not present, generate a remove request */
89: #ifdef S_IFLNK
90: if (lstat (file, &sb) < 0 && errno == ENOENT) {
91: #else
92: if (stat (file, &sb) < 0 && errno == ENOENT) {
93: #endif
94: fprintf (tf, "r ");
95: putpath (tf, transname (file));
96: putc ('\n', tf);
97: } else {
98: x = ftw (file, consider, 8);
99: if (x != 0) {
100: rc++;
101: if (x == -1)
102: perror (file);
103: }
104: }
105: }
106:
107: /*
108: * we are done building a package. This writes the actual file
109: * contents, so make sure the files are still around
110: */
111: int
112: pkgend(void)
113: {
114: register struct pack *pack;
115: struct stat s;
116:
117: /* write 'x' or 'X' execution item if requested */
118: if (xstr) {
119: fprintf (tf, "x ");
120: putpath (tf, xstr);
121: fprintf (tf, "\n");
122: }
123: if (Xstr) {
124: fprintf (tf, "X ");
125: putpath (tf, Xstr);
126: fprintf (tf, "\n");
127: }
128:
129: /* we now know how long the first component is */
130: pkhead->size = ftell (tf);
131:
132: /* we no longer need to write the temporary file */
133: fclose (tf);
134:
135: /* describe the temp file correctly so it will pass later checks */
136: if (pkhead->time == 0)
137: (void) time (&pkhead->time);
138: nchk (stat (tfname, &s));
139: pkhead->dev = s.st_dev;
140: pkhead->ino = s.st_ino;
141:
142: /*
143: * write the files out into an archive
144: */
145:
146: /* first the archive header */
147: printf (ARMAG);
148:
149: /*
150: * run through the list, creating the archive components
151: * and deleting the list entries. One iteration per component.
152: * We know there is at least one component, because the
153: * "Instructions" component must be represented.
154: */
155: do {
156: struct ar_hdr ah;
157: char buf[30];
158: register int c;
159:
160: /* "pack" is the package component under consideration */
161: pack = pkhead;
162:
163: if (pack->iname) { /* non-regular file entry, no data */
164:
165: /* log it if requested */
166: if (vflag)
167: fprintf (stderr, "package %s\n",
168: strcmp (pack->iname, instr)? pack->ename: instr);
169:
170: /* write the archive element header */
171:
172: # define ent(a,x) sprintf(buf, "%-*s", sizeof(ah.a), x); \
173: strncpy (ah.a, buf, sizeof (ah.a))
174: ent (ar_name, pack->iname);
175: ent (ar_fmag, ARFMAG);
176: # undef ent
177:
178: # define ent(a,x) sprintf(buf, "%*ld", sizeof(ah.a), (long) x); \
179: strncpy (ah.a, buf, sizeof (ah.a))
180: ent (ar_date, pack->time);
181: ent (ar_uid, pack->uid);
182: ent (ar_gid, pack->gid);
183: ent (ar_size, pack->size);
184: # undef ent
185:
186: # define ent(a,x) sprintf(buf, "%*o", sizeof(ah.a), x); \
187: strncpy (ah.a, buf, sizeof (ah.a))
188: ent (ar_mode, pack->mode);
189: # undef ent
190:
191: fwrite ((char *) &ah, sizeof (ah), 1, stdout);
192:
193: /* write the archive element itself */
194: tf = fopen (pack->ename, "r");
195: if (tf == NULL) {
196: perror (pack->iname);
197: exit (1);
198: }
199:
200: while ((c = getc (tf)) != EOF)
201: putchar (c);
202:
203: /* if things now don't match, complain */
204: if (fstat (fileno (tf), &s) < 0 || s.st_size != pack->size ||
205: (s.st_mtime != pack->time && strcmp (pack->iname, instr)) ||
206: s.st_dev != pack->dev || s.st_ino != pack->ino ||
207: s.st_uid != pack->uid || s.st_gid != pack->gid ||
208: (s.st_mode & 07777) != (pack->mode & 07777)) {
209: fprintf (stderr, "phase error on %s\n",
210: pack->ename);
211: rc++;
212: }
213:
214: fclose (tf);
215:
216: if (pack->size & 1)
217: putchar ('\n');
218: }
219:
220: /* delete the element, move on to the next */
221: if (pack->iname) free (pack->iname);
222: free (pack->ename);
223: pkhead = pack->link;
224: free ((char *) pack);
225: } while (pkhead);
226:
227: /* zap the tail pointer for general cleanliness */
228: pktail = NULL;
229:
230: nchk (unlink (tfname));
231: signal (SIGINT, sigsav);
232:
233: return rc;
234: }
235:
236: static void hdrsub(char *, struct stat *);
237: static char *iname(char *);
238:
239: /* internal function for package creation */
240: static int
241: consider (char *name, struct stat *buf, int type, struct FTW *ftw)
242: {
243: register struct pack *pack;
244: register int mode;
245: char *biname;
246: #ifdef S_ISLNK
247: char *slname;
248: #endif
249:
250: switch (type) {
251: case FTW_D:
252: fprintf (tf, "d %-*.4o ", MAXCOMP, buf->st_mode & 07777);
253: hdrsub (name, buf);
254: fprintf (tf, "\n");
255: break;
256:
257: case FTW_SL:
258: if (ftw->level == 0) {
259: ftw->quit = FTW_FOLLOW;
260: return 0;
261: }
262: /* fall through */
263:
264: case FTW_F:
265: mode = buf->st_mode;
266:
267: /* Has this file already appeared? If so, it's a link */
268: for (pack = pkhead->link; pack; pack = pack->link) {
269: if (buf->st_dev == pack->dev &&
270: buf->st_ino == pack->ino) {
271: fprintf (tf, "l %s ", transname (pack->ename));
272: fprintf (tf, "%s\n", transname (name));
273: return 0;
274: }
275: }
276:
277: if (S_ISREG(mode)) {
278: /* refuse to package the standard output */
279: if (buf->st_dev == outsb.st_dev &&
280: buf->st_ino == outsb.st_ino) {
281: fprintf (stderr, "skipping output file %s\n",
282: fullname (name));
283: return 0;
284: }
285: biname = iname (name);
286: fprintf (tf, "f ");
287: putpath (tf, biname);
288: fprintf (tf, " ");
289: hdrsub (name, buf);
290: fprintf (tf, "\n");
291: }
292: #ifdef S_ISLNK
293: else if (S_ISLNK(mode)) {
294: slname = alloc((unsigned)buf->st_size+1);
295: slname[buf->st_size] = '\0';
296: if (readlink(name, slname, buf->st_size) !=
297: buf->st_size) {
298: perror(name);
299: return (0);
300: }
301: fprintf (tf, "s %s ", transname (slname));
302: fprintf (tf, "%s\n", transname (name));
303: biname = NULL;
304: }
305: #endif
306: #if 0 /* We don't handle special files any more. */
307: else if (S_ISBLK(mode) || S_ISCHR(mode)) {
308: fprintf (tf, "%c %#o %d %d ",
309: mode == S_IFBLK? 'b': 'c',
310: buf->st_mode & 07777,
311: major (buf->st_rdev),
312: minor (buf->st_rdev));
313: hdrsub (name, buf);
314: fprintf (tf, "\n");
315: biname = NULL;
316: }
317: #endif
318: else {
319: fprintf (stderr, "%s: unrecognized file type\n",
320: fullname (name));
321: break;
322: }
323:
324:
325: /* package the file */
326: pack = new (struct pack);
327: pack->ename = copy (name);
328: pack->dev = buf->st_dev;
329: pack->ino = buf->st_ino;
330: pack->uid = buf->st_uid;
331: pack->gid = buf->st_gid;
332: pack->time = buf->st_mtime;
333: if (pack->time > pkhead->time)
334: pkhead->time = pack->time;
335: pack->size = buf->st_size;
336: pack->mode = buf->st_mode;
337: pack->link = NULL;
338: pack->iname = biname;
339: pktail->link = pack;
340: pktail = pack;
341: break;
342:
343: case FTW_DNR:
344: fprintf (stderr, "cannot read directory %s\n", name);
345: return 1;
346:
347: case FTW_NS:
348: fprintf (stderr, "cannot stat %s\n", name);
349: return 1;
350:
351: case FTW_DP:
352: break;
353:
354: default:
355: fprintf (stderr, "impossible code %d from ftw\n", type);
356: exit (1);
357: }
358: return 0;
359: }
360:
361: static void
362: hdrsub (char *name, struct stat *buf)
363: {
364: putpath (tf, uidstr (buf->st_uid));
365: putc ('\t', tf);
366: putpath (tf, gidstr (buf->st_gid));
367: putc ('\t', tf);
368: putpath (tf, transname (name));
369: }
370:
371: /*
372: * generate a unique internal name for a file
373: */
374: static char *
375: iname (char *s)
376: {
377: register char *p;
378: register char *lastcomp;
379: register struct pack *pack;
380: char trial[MAXCOMP+1];
381:
382: /* point lastcomp at the last pathname component */
383: lastcomp = s;
384: for (p = s; *p; p++) {
385: if (*p == '/')
386: lastcomp = p + 1;
387: }
388:
389: /* if the name is acceptably short, modify it slightly */
390: if (strlen (lastcomp) <= MAXCOMP) {
391:
392: char prefix[MAXCOMP+1], suffix[MAXCOMP+1], num[30];
393: register int n;
394:
395: /* split the name, remove unprintables */
396: strcpy (prefix, lastcomp);
397: for (p = prefix; *p; p++)
398: if (*p == ' ' || !isprint (*p))
399: *p = '$';
400: suffix[0] = '\0';
401: p = strrchr (prefix, '.');
402: if (p != NULL) {
403: strcpy (suffix, p);
404: *p = '\0';
405: }
406:
407: /* generate trial names until we run out of space */
408: for (n = 0, num[0] = '\0';
409: strlen(prefix) + strlen(suffix) + strlen(num) <= MAXCOMP;
410: n++, sprintf (num, "%.0d", n)) {
411:
412: /* generate the trial name */
413: strcpy (trial, prefix);
414: strcat (trial, num);
415: strcat (trial, suffix);
416:
417: /* if the name is unique, we're done */
418: pack = pkhead;
419: while (pack != NULL && strcmp (pack->iname, trial) != 0)
420: pack = pack->link;
421: if (pack == NULL)
422: return copy(trial);
423:
424: }
425: }
426:
427: /* punt -- generate a completely new name */
428: do {
429: static int tempno;
430:
431: tempno++;
432: sprintf (trial, "Temp%d", tempno);
433: pack = pkhead;
434: while (pack != NULL && strcmp (trial, pack->iname) != 0)
435: pack = pack->link;
436: } while (pack != NULL);
437: return copy(trial);
438: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.