00001
00002
00003
00004
00005
00006
00007
00008
00009 static char RcsId[] = "$Header: /opt/proj/minix/cvsroot/src/commands/aal/archiver.c,v 1.1.1.1 2005/04/21 14:53:57 beng Exp $";
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <sys/types.h>
00029 #include <sys/stat.h>
00030 #ifndef S_IREAD
00031 #define S_IREAD S_IRUSR
00032 #endif
00033 #ifndef S_IWRITE
00034 #define S_IWRITE S_IWUSR
00035 #endif
00036 #ifndef S_IEXEC
00037 #define S_IEXEC S_IXUSR
00038 #endif
00039 #include <signal.h>
00040 #include <arch.h>
00041 #ifdef AAL
00042 #include <ranlib.h>
00043 #include <out.h>
00044 #define MAGIC_NUMBER AALMAG
00045 long offset;
00046 struct ranlib *tab;
00047 unsigned int tnum = 0;
00048 char *tstrtab;
00049 unsigned int tssiz = 0;
00050 char *malloc(), *realloc(), *strcpy(), *strncpy();
00051 long time();
00052 unsigned int tabsz, strtabsz;
00053 #else
00054 #define MAGIC_NUMBER ARMAG
00055 #endif
00056 long lseek();
00057
00058 #define odd(nr) (nr & 01)
00059 #define even(nr) (odd(nr) ? nr + 1 : nr)
00060
00061 typedef char BOOL;
00062 #define FALSE 0
00063 #define TRUE 1
00064
00065 #define READ 0
00066 #define APPEND 2
00067 #define CREATE 1
00068
00069 #define MEMBER struct ar_hdr
00070
00071 #define NIL_PTR ((char *) 0)
00072 #define NIL_MEM ((MEMBER *) 0)
00073 #define NIL_LONG ((long *) 0)
00074
00075 #define IO_SIZE (10 * 1024)
00076
00077 #define equal(str1, str2) (!strncmp((str1), (str2), 14))
00078 #ifndef S_ISDIR
00079 #define S_ISDIR(m) (m & S_IFDIR)
00080 #endif
00081
00082 BOOL verbose;
00083 BOOL app_fl;
00084 BOOL ex_fl;
00085 BOOL show_fl;
00086 BOOL pr_fl;
00087 BOOL rep_fl;
00088 BOOL del_fl;
00089 BOOL nocr_fl;
00090 BOOL local_fl;
00091 BOOL update_fl;
00092 #ifdef DISTRIBUTION
00093 BOOL distr_fl;
00094 long distr_time;
00095 #endif
00096
00097 int ar_fd;
00098
00099 char io_buffer[IO_SIZE];
00100
00101 char *progname;
00102
00103 char temp_buf[32];
00104 char *temp_arch = &temp_buf[0];
00105 extern char *mktemp();
00106 extern char *ctime();
00107
00108 usage()
00109 {
00110 error(TRUE, "usage: %s %s archive [file] ...\n",
00111 progname,
00112 #ifdef AAL
00113 "[acdrtxvlu]"
00114 #else
00115 "[acdprtxvlu]"
00116 #endif
00117 );
00118 }
00119
00120
00121 error(quit, str1, str2, str3, str4)
00122 BOOL quit;
00123 char *str1, *str2, *str3, *str4;
00124 {
00125 char errbuf[256];
00126
00127 sprint(errbuf, str1, str2, str3, str4);
00128 write(2, errbuf, strlen(errbuf));
00129 if (quit) {
00130 unlink(temp_arch);
00131 _exit(1);
00132 }
00133 }
00134
00135 char *basename(path)
00136 char *path;
00137 {
00138 register char *ptr = path;
00139 register char *last = NIL_PTR;
00140
00141 while (*ptr != '\0') {
00142 if (*ptr == '/')
00143 last = ptr;
00144 ptr++;
00145 }
00146 if (last == NIL_PTR)
00147 return path;
00148 if (*(last + 1) == '\0') {
00149 *last = '\0';
00150 return basename(path);
00151 }
00152 return last + 1;
00153 }
00154
00155 extern unsigned int rd_unsigned2();
00156
00157 open_archive(name, mode)
00158 register char *name;
00159 register int mode;
00160 {
00161 unsigned short magic = 0;
00162 int fd;
00163
00164 if (mode == CREATE) {
00165 if ((fd = creat(name, 0666)) < 0)
00166 error(TRUE, "cannot creat %s\n", name);
00167 magic = MAGIC_NUMBER;
00168 wr_int2(fd, magic);
00169 return fd;
00170 }
00171
00172 if ((fd = open(name, mode)) < 0) {
00173 if (mode == APPEND) {
00174 close(open_archive(name, CREATE));
00175 if (!nocr_fl) error(FALSE, "%s: creating %s\n", progname, name);
00176 return open_archive(name, APPEND);
00177 }
00178 error(TRUE, "cannot open %s\n", name);
00179 }
00180 lseek(fd, 0L, 0);
00181 magic = rd_unsigned2(fd);
00182 if (magic != AALMAG && magic != ARMAG)
00183 error(TRUE, "%s is not in ar format\n", name);
00184
00185 return fd;
00186 }
00187
00188 #if __STDC__
00189 void catch(int sig)
00190 #else
00191 catch()
00192 #endif
00193 {
00194 unlink(temp_arch);
00195 _exit (2);
00196 }
00197
00198 main(argc, argv)
00199 int argc;
00200 char *argv[];
00201 {
00202 register char *ptr;
00203 int needs_arg = 0;
00204
00205 progname = argv[0];
00206
00207 if (argc < 3)
00208 usage();
00209
00210 for (ptr = argv[1]; *ptr; ptr++) {
00211 switch (*ptr) {
00212 case 't' :
00213 show_fl = TRUE;
00214 break;
00215 case 'v' :
00216 verbose = TRUE;
00217 break;
00218 case 'x' :
00219 ex_fl = TRUE;
00220 break;
00221 case 'a' :
00222 needs_arg = 1;
00223 app_fl = TRUE;
00224 break;
00225 case 'c' :
00226 nocr_fl = TRUE;
00227 break;
00228 #ifndef AAL
00229 case 'p' :
00230 needs_arg = 1;
00231 pr_fl = TRUE;
00232 break;
00233 #endif
00234 case 'd' :
00235 needs_arg = 1;
00236 del_fl = TRUE;
00237 break;
00238 case 'r' :
00239 needs_arg = 1;
00240 rep_fl = TRUE;
00241 break;
00242 case 'l' :
00243 local_fl = TRUE;
00244 break;
00245 case 'u' :
00246 update_fl = TRUE;
00247 break;
00248 #ifdef DISTRIBUTION
00249 case 'D' :
00250 distr_fl = TRUE;
00251 break;
00252 #endif
00253 default :
00254 usage();
00255 }
00256 }
00257
00258 if (needs_arg && argc <= 3)
00259 usage();
00260 #ifdef DISTRIBUTION
00261 if (distr_fl) {
00262 struct stat statbuf;
00263
00264 stat(progname, &statbuf);
00265 distr_time = statbuf.st_mtime;
00266 }
00267 #endif
00268 if (local_fl) strcpy(temp_arch, "ar.XXXXXX");
00269 else strcpy(temp_arch, "/usr/tmp/ar.XXXXXX");
00270
00271 if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1)
00272 usage();
00273
00274 if (update_fl && !rep_fl)
00275 usage();
00276
00277 if (rep_fl || del_fl
00278 #ifdef AAL
00279 || app_fl
00280 #endif
00281 ) {
00282 mktemp(temp_arch);
00283 }
00284 #ifdef AAL
00285 tab = (struct ranlib *) malloc(512 * sizeof(struct ranlib));
00286 tstrtab = malloc(4096);
00287 if (!tab || !tstrtab) error(TRUE,"Out of core\n");
00288 tabsz = 512;
00289 strtabsz = 4096;
00290 #endif
00291
00292 signal(SIGINT, catch);
00293 get(argc, argv);
00294
00295 return 0;
00296 }
00297
00298 MEMBER *
00299 get_member()
00300 {
00301 static MEMBER member;
00302
00303 again:
00304 if (rd_arhdr(ar_fd, &member) == 0)
00305 return NIL_MEM;
00306 if (member.ar_size < 0) {
00307 error(TRUE, "archive has member with negative size\n");
00308 }
00309 #ifdef AAL
00310 if (equal(SYMDEF, member.ar_name)) {
00311 lseek(ar_fd, member.ar_size, 1);
00312 goto again;
00313 }
00314 #endif
00315 return &member;
00316 }
00317
00318 char *get_mode();
00319
00320 get(argc, argv)
00321 int argc;
00322 register char *argv[];
00323 {
00324 register MEMBER *member;
00325 int i = 0;
00326 int temp_fd, read_chars;
00327
00328 ar_fd = open_archive(argv[2], (show_fl || pr_fl || ex_fl) ? READ : APPEND);
00329 if (rep_fl || del_fl
00330 #ifdef AAL
00331 || app_fl
00332 #endif
00333 )
00334 temp_fd = open_archive(temp_arch, CREATE);
00335 while ((member = get_member()) != NIL_MEM) {
00336 if (argc > 3) {
00337 for (i = 3; i < argc; i++) {
00338 if (equal(basename(argv[i]), member->ar_name))
00339 break;
00340 }
00341 if (i == argc || app_fl) {
00342 if (rep_fl || del_fl
00343 #ifdef AAL
00344 || app_fl
00345 #endif
00346 ) {
00347 #ifdef AAL
00348 if (i != argc) {
00349 print("%s: already in archive\n", argv[i]);
00350 argv[i] = "";
00351 }
00352 #endif
00353 wr_arhdr(temp_fd, member);
00354 copy_member(member, ar_fd, temp_fd, 0);
00355 }
00356 else {
00357 #ifndef AAL
00358 if (app_fl && i != argc) {
00359 print("%s: already in archive\n", argv[i]);
00360 argv[i] = "";
00361 }
00362 #endif
00363 lseek(ar_fd, even(member->ar_size),1);
00364 }
00365 continue;
00366 }
00367 }
00368 if (ex_fl || pr_fl)
00369 extract(member);
00370 else {
00371 if (rep_fl) {
00372 int isold = 0;
00373 if(update_fl) {
00374 struct stat status;
00375 if (stat(argv[i], &status) >= 0) {
00376 if(status.st_mtime <= member->ar_date)
00377 isold = 1;
00378 }
00379 }
00380 if(!isold)
00381 add(argv[i], temp_fd, "r - %s\n");
00382 else {
00383 wr_arhdr(temp_fd, member);
00384 copy_member(member, ar_fd, temp_fd, 0);
00385 if(verbose)
00386 show("r - %s (old)\n", member->ar_name);
00387 }
00388 }
00389 else if (show_fl) {
00390 char buf[sizeof(member->ar_name) + 2];
00391 register char *p = buf, *q = member->ar_name;
00392
00393 while (q <= &member->ar_name[sizeof(member->ar_name)-1] && *q) {
00394 *p++ = *q++;
00395 }
00396 *p++ = '\n';
00397 *p = '\0';
00398 if (verbose) {
00399 char *mode = get_mode(member->ar_mode);
00400 char *date = ctime(&(member->ar_date));
00401
00402 *(date + 16) = '\0';
00403 *(date + 24) = '\0';
00404
00405 print("%s%3u/%u%7ld %s %s %s",
00406 mode,
00407 (unsigned) (member->ar_uid & 0377),
00408 (unsigned) (member->ar_gid & 0377),
00409 member->ar_size,
00410 date+4,
00411 date+20,
00412 buf);
00413 }
00414 else print(buf);
00415 }
00416 else if (del_fl)
00417 show("d - %s\n", member->ar_name);
00418 lseek(ar_fd, even(member->ar_size), 1);
00419 }
00420 argv[i] = "";
00421 }
00422
00423 if (argc > 3) {
00424 for (i = 3; i < argc; i++)
00425 if (argv[i][0] != '\0') {
00426 #ifndef AAL
00427 if (app_fl)
00428 add(argv[i], ar_fd, "a - %s\n");
00429 else
00430 #endif
00431 if (rep_fl
00432 #ifdef AAL
00433 || app_fl
00434 #endif
00435 )
00436 add(argv[i], temp_fd, "a - %s\n");
00437 else {
00438 print("%s: not found\n", argv[i]);
00439 }
00440 }
00441 }
00442
00443 if (rep_fl || del_fl
00444 #ifdef AAL
00445 || app_fl
00446 #endif
00447 ) {
00448 signal(SIGINT, SIG_IGN);
00449 close(ar_fd);
00450 close(temp_fd);
00451 ar_fd = open_archive(argv[2], CREATE);
00452 temp_fd = open_archive(temp_arch, APPEND);
00453 #ifdef AAL
00454 write_symdef();
00455 #endif
00456 while ((read_chars = read(temp_fd, io_buffer, IO_SIZE)) > 0)
00457 mwrite(ar_fd, io_buffer, read_chars);
00458 close(temp_fd);
00459 unlink(temp_arch);
00460 }
00461 close(ar_fd);
00462 }
00463
00464 add(name, fd, mess)
00465 char *name;
00466 int fd;
00467 char *mess;
00468 {
00469 static MEMBER member;
00470 register int read_chars;
00471 struct stat status;
00472 int src_fd;
00473
00474 if (stat(name, &status) < 0) {
00475 error(FALSE, "cannot find %s\n", name);
00476 return;
00477 }
00478 else if (S_ISDIR(status.st_mode)) {
00479 error(FALSE, "%s is a directory (ignored)\n", name);
00480 return;
00481 }
00482 else if ((src_fd = open(name, 0)) < 0) {
00483 error(FALSE, "cannot open %s\n", name);
00484 return;
00485 }
00486
00487 strncpy (member.ar_name, basename (name), sizeof(member.ar_name));
00488 member.ar_uid = status.st_uid;
00489 member.ar_gid = status.st_gid;
00490 member.ar_mode = status.st_mode;
00491 member.ar_date = status.st_mtime;
00492 member.ar_size = status.st_size;
00493 #ifdef DISTRIBUTION
00494 if (distr_fl) {
00495 member.ar_uid = 2;
00496 member.ar_gid = 2;
00497 member.ar_mode = 0644;
00498 member.ar_date = distr_time;
00499 }
00500 #endif
00501 wr_arhdr(fd, &member);
00502 #ifdef AAL
00503 do_object(src_fd, member.ar_size);
00504 lseek(src_fd, 0L, 0);
00505 offset += AR_TOTAL + even(member.ar_size);
00506 #endif
00507 while (status.st_size > 0) {
00508 int x = IO_SIZE;
00509
00510 read_chars = x;
00511 if (status.st_size < x) {
00512 x = status.st_size;
00513 read_chars = x;
00514 status.st_size = 0;
00515 x = even(x);
00516 }
00517 else status.st_size -= x;
00518 if (read(src_fd, io_buffer, read_chars) != read_chars) {
00519 error(FALSE,"%s seems to shrink\n", name);
00520 break;
00521 }
00522 mwrite(fd, io_buffer, x);
00523 }
00524
00525 if (verbose)
00526 show(mess, member.ar_name);
00527 close(src_fd);
00528 }
00529
00530 extract(member)
00531 register MEMBER *member;
00532 {
00533 int fd = 1;
00534 char buf[sizeof(member->ar_name) + 1];
00535
00536 strncpy(buf, member->ar_name, sizeof(member->ar_name));
00537 buf[sizeof(member->ar_name)] = 0;
00538 if (pr_fl == FALSE && (fd = creat(buf, 0666)) < 0) {
00539 error(FALSE, "cannot create %s\n", buf);
00540 fd = -1;
00541 }
00542
00543 if (verbose) {
00544 if (pr_fl == FALSE) show("x - %s\n", buf);
00545 else show("\n<%s>\n\n", buf);
00546 }
00547
00548 copy_member(member, ar_fd, fd, 1);
00549
00550 if (fd >= 0 && fd != 1)
00551 close(fd);
00552 if (pr_fl == FALSE) chmod(buf, member->ar_mode);
00553 }
00554
00555 copy_member(member, from, to, extracting)
00556 register MEMBER *member;
00557 int from, to;
00558 {
00559 register int rest;
00560 long mem_size = member->ar_size;
00561 BOOL is_odd = odd(mem_size) ? TRUE : FALSE;
00562
00563 #ifdef AAL
00564 if (! extracting) {
00565 long pos = lseek(from, 0L, 1);
00566
00567 do_object(from, mem_size);
00568 offset += AR_TOTAL + even(mem_size);
00569 lseek(from, pos, 0);
00570 }
00571 #endif
00572 do {
00573 rest = mem_size > (long) IO_SIZE ? IO_SIZE : (int) mem_size;
00574 if (read(from, io_buffer, rest) != rest) {
00575 char buf[sizeof(member->ar_name) + 1];
00576
00577 strncpy(buf, member->ar_name, sizeof(member->ar_name));
00578 buf[sizeof(member->ar_name)] = 0;
00579 error(TRUE, "read error on %s\n", buf);
00580 }
00581 if (to >= 0) mwrite(to, io_buffer, rest);
00582 mem_size -= (long) rest;
00583 } while (mem_size > 0L);
00584
00585 if (is_odd) {
00586 lseek(from, 1L, 1);
00587 if (to >= 0 && ! extracting)
00588 lseek(to, 1L, 1);
00589 }
00590 }
00591
00592 char *
00593 get_mode(mode)
00594 register int mode;
00595 {
00596 static char mode_buf[11];
00597 register int tmp = mode;
00598 int i;
00599
00600 mode_buf[9] = ' ';
00601 for (i = 0; i < 3; i++) {
00602 mode_buf[i * 3] = (tmp & S_IREAD) ? 'r' : '-';
00603 mode_buf[i * 3 + 1] = (tmp & S_IWRITE) ? 'w' : '-';
00604 mode_buf[i * 3 + 2] = (tmp & S_IEXEC) ? 'x' : '-';
00605 tmp <<= 3;
00606 }
00607 if (mode & S_ISUID)
00608 mode_buf[2] = 's';
00609 if (mode & S_ISGID)
00610 mode_buf[5] = 's';
00611 return mode_buf;
00612 }
00613
00614 wr_fatal()
00615 {
00616 error(TRUE, "write error\n");
00617 }
00618
00619 rd_fatal()
00620 {
00621 error(TRUE, "read error\n");
00622 }
00623
00624 mwrite(fd, address, bytes)
00625 int fd;
00626 register char *address;
00627 register int bytes;
00628 {
00629 if (write(fd, address, bytes) != bytes)
00630 error(TRUE, "write error\n");
00631 }
00632
00633 show(s, name)
00634 char *s, *name;
00635 {
00636 MEMBER x;
00637 char buf[sizeof(x.ar_name)+1];
00638 register char *p = buf, *q = name;
00639
00640 while (q <= &name[sizeof(x.ar_name)-1] && *q) *p++ = *q++;
00641 *p++ = '\0';
00642 print(s, buf);
00643 }
00644
00645 #ifdef AAL
00646
00647
00648
00649
00650
00651
00652 write_symdef()
00653 {
00654 register struct ranlib *ran;
00655 register int i;
00656 register long delta;
00657 MEMBER arbuf;
00658
00659 if (odd(tssiz))
00660 tstrtab[tssiz++] = '\0';
00661 for (i = 0; i < sizeof(arbuf.ar_name); i++)
00662 arbuf.ar_name[i] = '\0';
00663 strcpy(arbuf.ar_name, SYMDEF);
00664 arbuf.ar_size = 4 + 2 * 4 * (long)tnum + 4 + (long)tssiz;
00665 time(&arbuf.ar_date);
00666 arbuf.ar_uid = getuid();
00667 arbuf.ar_gid = getgid();
00668 arbuf.ar_mode = 0444;
00669 #ifdef DISTRIBUTION
00670 if (distr_fl) {
00671 arbuf.ar_uid = 2;
00672 arbuf.ar_gid = 2;
00673 arbuf.ar_date = distr_time;
00674 }
00675 #endif
00676 wr_arhdr(ar_fd,&arbuf);
00677 wr_long(ar_fd, (long) tnum);
00678
00679
00680
00681
00682 delta = 2 + AR_TOTAL + arbuf.ar_size;
00683 for (ran = tab; ran < &tab[tnum]; ran++) {
00684 ran->ran_pos += delta;
00685 }
00686
00687 wr_ranlib(ar_fd, tab, (long) tnum);
00688 wr_long(ar_fd, (long) tssiz);
00689 wr_bytes(ar_fd, tstrtab, (long) tssiz);
00690 }
00691
00692
00693
00694
00695
00696 int
00697 is_outhead(headp)
00698 register struct outhead *headp;
00699 {
00700
00701 return !BADMAGIC(*headp) && headp->oh_nname != 0;
00702 }
00703
00704 do_object(f, size)
00705 long size;
00706 {
00707 struct outhead headbuf;
00708
00709 if (size < SZ_HEAD) {
00710
00711 return;
00712 }
00713
00714
00715
00716 if (! rd_fdopen(f)) {
00717 rd_fatal();
00718 }
00719 rd_ohead(&headbuf);
00720 if (!is_outhead(&headbuf)) {
00721 return;
00722 }
00723 do_names(&headbuf);
00724 }
00725
00726
00727
00728
00729
00730
00731 do_names(headp)
00732 struct outhead *headp;
00733 {
00734 register char *strings;
00735 register int nnames = headp->oh_nname;
00736 #define NNAMES 100
00737 struct outname namebuf[NNAMES];
00738 long xxx = OFF_CHAR(*headp);
00739
00740 if ( headp->oh_nchar != (unsigned int)headp->oh_nchar ||
00741 (strings = malloc((unsigned int)headp->oh_nchar)) == (char *)0
00742 ) {
00743 error(TRUE, "string table too big\n");
00744 }
00745 rd_string(strings, headp->oh_nchar);
00746 while (nnames) {
00747 int i = nnames >= NNAMES ? NNAMES : nnames;
00748 register struct outname *p = namebuf;
00749
00750 nnames -= i;
00751 rd_name(namebuf, i);
00752 while (i--) {
00753 long off = p->on_foff - xxx;
00754 if (p->on_foff == (long)0) {
00755 p++;
00756 continue;
00757 }
00758 p->on_mptr = strings + off;
00759
00760
00761
00762
00763
00764
00765
00766
00767 if ( (p->on_type & S_EXT) &&
00768 (p->on_type & S_TYP) != S_UND
00769 )
00770 enter_name(p);
00771 p++;
00772 }
00773 }
00774 free(strings);
00775 }
00776
00777 enter_name(namep)
00778 struct outname *namep;
00779 {
00780 register char *cp;
00781
00782 if (tnum >= tabsz) {
00783 tab = (struct ranlib *)
00784 realloc((char *) tab, (tabsz += 512) * sizeof(struct ranlib));
00785 if (! tab) error(TRUE, "Out of core\n");
00786 }
00787 tab[tnum].ran_off = tssiz;
00788 tab[tnum].ran_pos = offset;
00789
00790 for (cp = namep->on_mptr;; cp++) {
00791 if (tssiz >= strtabsz) {
00792 tstrtab = realloc(tstrtab, (strtabsz += 4096));
00793 if (! tstrtab) error(TRUE, "string table overflow\n");
00794 }
00795 tstrtab[tssiz++] = *cp;
00796 if (!*cp) break;
00797 }
00798 tnum++;
00799 }
00800 #endif AAL