BSD 2 development
[unix-history] / misc / ar.c
CommitLineData
5d6c246c
BJ
1#define NARMAG 0177545
2struct
3{
4 char name[14];
5 long date;
6 char uid;
7 char gid;
8 int mode;
9 long size;
10} arbuf;
11struct
12{
13 char minor;
14 char major;
15 int inumber;
16 int flags;
17 char nlinks;
18 char usrid;
19 char grpid;
20 char siz0;
21 int siz1;
22 int addr[8];
23 long adate;
24 long mdate;
25} stbuf;
26
27#define SKIP 1
28#define IODD 2
29#define OODD 4
30#define HEAD 8
31
32char *man { "mrxtdp" };
33char *opt { "uvnbai" };
34
35long itol();
36int done();
37int rcmd();
38int dcmd();
39int xcmd();
40int tcmd();
41int pcmd();
42int mcmd();
43int (*comfun)();
44char flg[26];
45char **namv;
46int namc;
47char *arnam;
48char *ponam;
49char *tfnam;
50char *tf1nam;
51char *tf2nam;
52char *file;
53char name[16];
54int af;
55int tf;
56int tf1;
57int tf2;
58int bastate;
59int buf[256];
60
61main(argc, argv)
62char *argv[];
63{
64 register i;
65 register char *cp;
66
67 for(i=1; i<4; i++)
68 if((signal(i, 1) & 1) == 0)
69 signal(i, done);
70 if(argc < 3)
71 usage();
72 cp = argv[1];
73 for(cp = argv[1]; *cp; cp++)
74 switch(*cp) {
75 case 'v':
76 case 'u':
77 case 'n':
78 case 'a':
79 case 'b':
80 case 'i':
81 flg[*cp - 'a']++;
82 continue;
83
84 case 'r':
85 setcom(rcmd);
86 continue;
87
88 case 'd':
89 setcom(dcmd);
90 continue;
91
92 case 'x':
93 setcom(xcmd);
94 continue;
95
96 case 't':
97 setcom(tcmd);
98 continue;
99
100 case 'p':
101 setcom(pcmd);
102 continue;
103
104 case 'm':
105 setcom(mcmd);
106 continue;
107
108 default:
109 printf("bad option `%c'\n", *cp);
110 done();
111 }
112 if(flg['i'-'a'])
113 flg['b'-'a']++;
114 if(flg['a'-'a'] || flg['b'-'a']) {
115 bastate = 1;
116 ponam = trim(argv[2]);
117 argv++;
118 argc--;
119 if(argc < 3)
120 usage();
121 }
122 arnam = argv[2];
123 namv = argv+3;
124 namc = argc-3;
125 if(comfun == 0) {
126 if(flg['u'-'a'] == 0) {
127 printf("one of [%s] must be specified\n", man);
128 done();
129 }
130 setcom(rcmd);
131 }
132 (*comfun)();
133 notfound();
134 done();
135}
136
137setcom(fun)
138int (*fun)();
139{
140
141 if(comfun != 0) {
142 printf("only one of [%s] allowed\n", man);
143 done();
144 }
145 comfun = fun;
146}
147
148rcmd()
149{
150 register f;
151
152 init();
153 if(getaf()) {
154 printf("creating %s\n", arnam);
155 cleanup();
156 return;
157 }
158 while(!getdir()) {
159 bamatch();
160 if(namc == 0 || match()) {
161 f = stats();
162 if(f < 0) {
163 if(namc)
164 printf("cannot open %s\n", file);
165 goto cp;
166 }
167 if(flg['u'-'a'])
168 if(stbuf.mdate <= arbuf.date) {
169 close(f);
170 goto cp;
171 }
172 mesg('r');
173 copyfil(af, -1, IODD+SKIP);
174 movefil(f);
175 continue;
176 }
177 cp:
178 mesg('c');
179 copyfil(af, tf, IODD+OODD+HEAD);
180 }
181 cleanup();
182}
183
184dcmd()
185{
186
187 init();
188 if(getaf())
189 noar();
190 while(!getdir()) {
191 if(match()) {
192 mesg('d');
193 copyfil(af, -1, IODD+SKIP);
194 continue;
195 }
196 mesg('c');
197 copyfil(af, tf, IODD+OODD+HEAD);
198 }
199 install();
200}
201
202xcmd()
203{
204 register f;
205
206 if(getaf())
207 noar();
208 while(!getdir()) {
209 if(namc == 0 || match()) {
210 f = creat(file, arbuf.mode & 0777);
211 if(f < 0) {
212 printf("%s cannot create\n", file);
213 goto sk;
214 }
215 mesg('x');
216 copyfil(af, f, IODD);
217 close(f);
218 continue;
219 }
220 sk:
221 mesg('c');
222 copyfil(af, -1, IODD+SKIP);
223 }
224}
225
226pcmd()
227{
228
229 if(getaf())
230 noar();
231 while(!getdir()) {
232 if(namc == 0 || match()) {
233 if(flg['v'-'a'])
234 printf("<%s>\n", file);
235 copyfil(af, 1, IODD);
236 continue;
237 }
238 copyfil(af, -1, IODD+SKIP);
239 }
240}
241
242mcmd()
243{
244
245 init();
246 if(getaf())
247 noar();
248 tf2nam = mktemp("/tmp/v2XXXXX");
249 close(creat(tf2nam, 0600));
250 tf2 = open(tf2nam, 2);
251 if(tf2 < 0) {
252 printf("cannot create third temp\n");
253 done();
254 }
255 while(!getdir()) {
256 bamatch();
257 if(match()) {
258 mesg('m');
259 copyfil(af, tf2, IODD+OODD+HEAD);
260 continue;
261 }
262 mesg('c');
263 copyfil(af, tf, IODD+OODD+HEAD);
264 }
265 install();
266}
267
268tcmd()
269{
270
271 if(getaf())
272 noar();
273 while(!getdir()) {
274 if(namc == 0 || match()) {
275 if(flg['v'-'a'])
276 longt();
277 printf("%s\n", trim(file));
278 }
279 copyfil(af, -1, IODD+SKIP);
280 }
281}
282
283init()
284{
285
286 tfnam = mktemp("/tmp/vXXXXX");
287 close(creat(tfnam, 0600));
288 tf = open(tfnam, 2);
289 if(tf < 0) {
290 printf("cannot create temp file\n");
291 done();
292 }
293 buf[0] = NARMAG;
294 if(write(tf, buf, 2) != 2) {
295 perror(tfnam);
296 done();
297 }
298}
299
300getaf()
301{
302
303 af = open(arnam, 0);
304 if(af < 0)
305 return(1);
306 buf[0] = 0;
307 read(af, buf, 2);
308 if(buf[0] != NARMAG) {
309 printf("%s not in archive format\n", arnam);
310 done();
311 }
312 return(0);
313}
314
315usage()
316{
317 printf("usage: ar [%s][%s] archive files ...\n", opt, man);
318 done();
319}
320
321noar()
322{
323
324 printf("%s does not exist\n", arnam);
325 done();
326}
327
328done()
329{
330
331 if(tfnam)
332 unlink(tfnam);
333 if(tf1nam)
334 unlink(tf1nam);
335 if(tf2nam)
336 unlink(tf2nam);
337 exit();
338}
339
340notfound()
341{
342 register i;
343
344 for(i=0; i<namc; i++)
345 if(namv[i])
346 printf("%s not found\n", namv[i]);
347}
348
349cleanup()
350{
351 register i, f;
352
353 for(i=0; i<namc; i++) {
354 file = namv[i];
355 if(file == 0)
356 continue;
357 namv[i] = 0;
358 mesg('a');
359 f = stats();
360 if(f < 0) {
361 printf("%s cannot open\n", file);
362 continue;
363 }
364 movefil(f);
365 }
366 install();
367}
368
369install()
370{
371 register i;
372
373 for(i=1; i<4; i++)
374 signal(i, 1);
375 close(af);
376 af = creat(arnam, 0644);
377 if(af < 0) {
378 printf("cannot create %s\n", arnam);
379 done();
380 }
381 seek(tf, 0, 0);
382 while((i = read(tf, buf, 512)) > 0)
383 if(write(af, buf, i) != i) {
384 perror(arnam);
385 done();
386 }
387 if(tf2nam) {
388 seek(tf2, 0, 0);
389 while((i = read(tf2, buf, 512)) > 0)
390 if(write(af, buf, i) != i) {
391 perror(arnam);
392 done();
393 }
394 }
395 if(tf1nam) {
396 seek(tf1, 0, 0);
397 while((i = read(tf1, buf, 512)) > 0)
398 if(write(af, buf, i) != i) {
399 perror(arnam);
400 done();
401 }
402 }
403}
404
405/*
406 * insert the file 'file'
407 * into the temporary file
408 */
409movefil(f)
410{
411 register char *cp;
412 register i;
413
414 cp = trim(file);
415 for(i=0; i<14; i++)
416 if(arbuf.name[i] = *cp)
417 cp++;
418 arbuf.size = itol(stbuf.siz0&0377, stbuf.siz1);
419 arbuf.date = stbuf.mdate;
420 arbuf.uid = stbuf.usrid;
421 arbuf.gid = stbuf.grpid;
422 arbuf.mode = stbuf.flags;
423 copyfil(f, tf, OODD+HEAD);
424 close(f);
425}
426
427stats()
428{
429 register f;
430
431 f = open(file, 0);
432 if(f < 0)
433 return(f);
434 if(fstat(f, &stbuf) < 0) {
435 close(f);
436 return(-1);
437 }
438 return(f);
439}
440
441/*
442 * copy next file
443 * size given in arbuf
444 */
445copyfil(fi, fo, flag)
446{
447 register i, o;
448 int pe;
449
450 if((flag & HEAD) && fo >= 0)
451 if(write(fo, &arbuf, sizeof arbuf) != sizeof arbuf) {
452 perror("write");
453 done();
454 }
455 pe = 0;
456 while(arbuf.size > 0) {
457 i = o = 512;
458 if(arbuf.size < i) {
459 i = o = arbuf.size;
460 if(i&1) {
461 if(flag & IODD)
462 i++;
463 if(flag & OODD)
464 o++;
465 }
466 }
467 if(read(fi, buf, i) != i)
468 pe++;
469 if((flag & SKIP) == 0)
470 if(write(fo, buf, o) != o && fo >= 0) {
471 perror("write");
472 done();
473 }
474 arbuf.size =- 512;
475 }
476 if(pe)
477 phserr();
478}
479
480getdir()
481{
482 register i;
483
484 i = read(af, &arbuf, sizeof arbuf);
485 if(i != sizeof arbuf) {
486 if(tf1nam) {
487 i = tf;
488 tf = tf1;
489 tf1 = i;
490 }
491 return(1);
492 }
493 for(i=0; i<14; i++)
494 name[i] = arbuf.name[i];
495 file = name;
496 return(0);
497}
498
499match()
500{
501 register i;
502
503 for(i=0; i<namc; i++) {
504 if(namv[i] == 0)
505 continue;
506 if(equal(trim(namv[i]), file)) {
507 file = namv[i];
508 namv[i] = 0;
509 return(1);
510 }
511 }
512 return(0);
513}
514
515bamatch()
516{
517 register f;
518
519 switch(bastate) {
520
521 case 1:
522 if(!equal(file, ponam))
523 return;
524 bastate = 2;
525 if(flg['a'-'a'])
526 return;
527
528 case 2:
529 bastate = 0;
530 tf1nam = mktemp("/tmp/v1XXXXX");
531 close(creat(tf1nam, 0600));
532 f = open(tf1nam, 2);
533 if(f < 0) {
534 printf("cannot create second temp\n");
535 return;
536 }
537 tf1 = tf;
538 tf = f;
539 }
540}
541
542equal(s1, s2)
543char *s1, *s2;
544{
545 register char *p1, *p2;
546
547 p1 = s1;
548 p2 = s2;
549 while(*p1++ == *p2)
550 if(*p2++ == 0)
551 return(1);
552 return(0);
553}
554
555phserr()
556{
557
558 printf("phase error on %s\n", file);
559}
560
561mesg(c)
562{
563
564 if(flg['v'-'a'])
565 if(c != 'c' || flg['v'-'a'] > 1)
566 printf("%c - %s\n", c, file);
567}
568
569trim(s)
570char *s;
571{
572 register char *p1, *p2;
573
574 for(p1 = s; *p1; p1++)
575 ;
576 while(p1 > s) {
577 if(*--p1 != '/')
578 break;
579 *p1 = 0;
580 }
581 p2 = s;
582 for(p1 = s; *p1; p1++)
583 if(*p1 == '/')
584 p2 = p1+1;
585 return(p2);
586}
587
588#define IFMT 060000
589#define ISARG 01000
590#define LARGE 010000
591#define SUID 04000
592#define SGID 02000
593#define ROWN 0400
594#define WOWN 0200
595#define XOWN 0100
596#define RGRP 040
597#define WGRP 020
598#define XGRP 010
599#define ROTH 04
600#define WOTH 02
601#define XOTH 01
602#define STXT 01000
603
604longt()
605{
606 register char *cp;
607 register t;
608
609 pmode();
610 printf("%3d/%1d", arbuf.uid&0377, arbuf.gid&0377);
611 printf("%6s", locv(arbuf.size));
612 cp = ctime(&arbuf.date);
613 printf(" %-12.12s %-4.4s ", cp+4, cp+20);
614}
615
616int m1[] { 1, ROWN, 'r', '-' };
617int m2[] { 1, WOWN, 'w', '-' };
618int m3[] { 2, SUID, 's', XOWN, 'x', '-' };
619int m4[] { 1, RGRP, 'r', '-' };
620int m5[] { 1, WGRP, 'w', '-' };
621int m6[] { 2, SGID, 's', XGRP, 'x', '-' };
622int m7[] { 1, ROTH, 'r', '-' };
623int m8[] { 1, WOTH, 'w', '-' };
624int m9[] { 2, STXT, 't', XOTH, 'x', '-' };
625
626int *m[] { m1, m2, m3, m4, m5, m6, m7, m8, m9};
627
628pmode()
629{
630 register int **mp;
631
632 for (mp = &m[0]; mp < &m[9];)
633 select(*mp++);
634}
635
636select(pairp)
637int *pairp;
638{
639 register int n, *ap;
640
641 ap = pairp;
642 n = *ap++;
643 while (--n>=0 && (arbuf.mode&*ap++)==0)
644 ap++;
645 putchar(*ap);
646}