home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / programm / programi / gcc_9112.lzh / gnu-src / ar.c next >
Encoding:
C/C++ Source or Header  |  1991-10-09  |  46.2 KB  |  2,030 lines

  1. /* ar.c - Archive modify and extract.
  2.    Copyright (C) 1988 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <stdio.h>
  19. #include <ar.h>
  20. #include <errno.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23.  
  24. #if !defined(A_OUT) && !defined(MACH_O)
  25. #define A_OUT
  26. #endif
  27.  
  28. #ifdef A_OUT
  29. #ifdef COFF_ENCAPSULATE
  30. #include "a.out.encap.h"
  31. #else
  32. #include <a.out.h>
  33. #endif
  34. #endif
  35.  
  36. #ifdef MACH_O
  37. #ifndef A_OUT
  38. #include <nlist.h>
  39. #endif
  40. #include <sys/loader.h>
  41. #endif
  42.  
  43. #ifdef USG
  44. #include <time.h>
  45. #include <fcntl.h>
  46. #else
  47. #include <sys/file.h>
  48. #include <sys/time.h>
  49. #endif
  50.  
  51. #ifdef    __GNUC__
  52. #ifndef MCH_AMIGA
  53. #define    alloca    __builtin_alloca
  54. #endif
  55. #else
  56. # ifdef sparc
  57. #  include <alloca.h>
  58. # else
  59. char *alloca ();
  60. # endif
  61. #endif
  62.  
  63. #ifdef    USG
  64. #define    bcopy(source, dest, size)    memcpy((dest), (source), (size))
  65. #define    bcmp(a, b, size)        memcmp((a), (b), (size))
  66. #define    bzero(s, size)            memset((s), 0, (size))
  67. #endif
  68.  
  69. /* Locking is normally disabled because fcntl hangs on the Sun
  70.    and it isn't supported properly across NFS anyway.  */
  71. #ifdef LOCKS
  72. /* You might need to compile with -I/usr/include/sys if your fcntl.h
  73.    isn't in /usr/include (which is where it should be according to POSIX).  */
  74. #include <fcntl.h>
  75. #endif
  76.  
  77. /* This structure is used internally to represent the info
  78.    on a member of an archive.  This is to make it easier to change format.  */
  79.  
  80. struct member_desc
  81.   {
  82.     /* Name of member.  */
  83.     char *name;
  84.  
  85.     /* The following fields are stored in the member header as decimal or octal
  86.        numerals, but in this structure they are stored as machine numbers.  */
  87.     int mode;        /* Protection mode from member header.  */
  88.     long int date;    /* Last modify date as stored in member header.  */
  89.     unsigned int size;    /* Bytes of member's data, from member header.  */
  90.     int uid, gid;    /* UID and GID fields copied from member header.  */
  91.     unsigned int offset;/* Offset in archive of the header of this member.  */
  92.     unsigned int data_offset;/* Offset of first data byte of the member.  */
  93.  
  94.     /* The next field does not describe where the member was in the
  95.        old archive, but rather where it will be in the modified archive.
  96.        It is set up by write_archive.  */
  97.     unsigned int new_offset;    /* Offset of this member in new archive */
  98.  
  99.     /* Symdef data for member.  Used only for files being inserted.  */
  100.     struct symdef *symdefs;
  101.     unsigned int nsymdefs;    /* Number of entries of symdef data.  */
  102.     unsigned int string_size;    /* Size of strings needed by symdef data.  */
  103.   };
  104.  
  105. /* Each symbol is recorded by something like this.  */
  106.  
  107. struct symdef
  108.   {
  109.     union
  110.       {
  111.     unsigned long int stringoffset;
  112.     char *name;
  113.       } s;
  114.     unsigned long int offset;
  115.   };
  116.  
  117. /* Nonzero means it's the name of an existing member;
  118.    position new or moved files with respect to this one.  */
  119.  
  120. char *posname;
  121.  
  122.  
  123. /* How to use `posname':
  124.    POS_BEFORE means position before that member.
  125.    POS_AFTER means position after that member.
  126.    POS_DEFAULT if position by default; then `posname' should also be zero. */
  127.  
  128. enum { POS_DEFAULT, POS_BEFORE, POS_AFTER } postype;
  129.  
  130. /* Nonzero means describe each action performed.  */
  131.  
  132. int verbose;
  133.  
  134. /* Nonzero means don't warn about creating the archive file if necessary.  */
  135.  
  136. int silent_create;
  137.  
  138. /* Nonzero means don't replace existing members whose
  139.    dates are more recent than the corresponding files.  */
  140.  
  141. int newer_only;
  142.  
  143. /* Nonzero means preserve dates of members when extracting them.  */
  144.  
  145. int preserve_dates;
  146.  
  147. /* Operation to be performed.  */
  148.  
  149. #define DELETE 1
  150. #define REPLACE 2
  151. #define PRINT_TABLE 3
  152. #define PRINT_FILES 4
  153. #define EXTRACT 5
  154. #define MOVE 6
  155. #define QUICK_APPEND 7
  156.  
  157. int operation;
  158.  
  159. /* Name of archive file.  */
  160.  
  161. char *archive;
  162.  
  163. /* Descriptor on which we have locked the original archive file,
  164.    or -1 if this has not been done.  */
  165.  
  166. int lock_indesc;
  167.  
  168. /* Pointer to tail of `argv', at first subfile name argument,
  169.  or zero if no such were specified.  */
  170.  
  171. char **files;
  172.  
  173. /* Nonzero means write a __.SYMDEF member into the modified archive.  */
  174.  
  175. int symdef_flag;
  176.  
  177. /* Nonzero means __.SYMDEF member exists in old archive.  */
  178.  
  179. int symdef_exists;
  180.  
  181. /* Nonzero means don't update __.SYMDEF unless the flag was given.  */
  182.  
  183. int ignore_symdef;
  184.  
  185. /* Total number of symdef entries we will have. */
  186.  
  187. unsigned long int nsymdefs;
  188.  
  189. /* Symdef data from old archive (set up only if we need it) */
  190.  
  191. struct symdef *old_symdefs;
  192.  
  193. /* Number of symdefs in remaining in old_symdefs.  */
  194.  
  195. unsigned int num_old_symdefs;
  196.  
  197. /* Number of symdefs old_symdefs had when it was read in.  */
  198.  
  199. unsigned long int original_num_symdefs;
  200.  
  201. /* String table from old __.SYMDEF member.  */
  202.  
  203. char *old_strings;
  204.  
  205. /* Size of old_strings */
  206.  
  207. unsigned long int old_strings_size;
  208.  
  209. /* String table to be written into __.SYMDEF member.  */
  210.  
  211. char *new_strings;
  212.  
  213. /* Size of new_strings */
  214.  
  215. unsigned long int new_strings_size;
  216.  
  217. /* An archive map is a chain of these structures.
  218.   Each structure describes one member of the archive.
  219.   The chain is in the same order as the members are.  */
  220.  
  221. struct mapelt
  222.   {
  223.     struct member_desc info;
  224.     struct mapelt *next;
  225.   };
  226.  
  227. struct mapelt *maplast;
  228.  
  229. /* If nonzero, this is the map-element for the __.SYMDEF member
  230.    and we should update the time of that member just before finishing.  */
  231.  
  232. struct mapelt *symdef_mapelt;
  233.  
  234. /* Header that we wrote for the __.SYMDEF member.  */
  235.  
  236. struct ar_hdr symdef_header;
  237.  
  238. char *xmalloc (), *xrealloc ();
  239. void free ();
  240.  
  241. void add_to_map (), delete_from_map ();
  242. int insert_in_map ();
  243. void print_descr ();
  244. char *concat ();
  245. void scan ();
  246. void extract_members ();
  247. void extract_member ();
  248. void print_contents ();
  249. void write_symdef_member ();
  250. void read_old_symdefs ();
  251. void two_operations ();
  252. void usage (), fatal (), error (), error_with_file ();
  253. void perror_with_name (), pfatal_with_name ();
  254. void write_archive ();
  255. void touch_symdef_member ();
  256. void update_symdefs ();
  257. void delete_members (), move_members (), replace_members ();
  258. void quick_append ();
  259.  
  260. /* Output BYTES of data at BUF to the descriptor DESC.
  261.    FILE is the name of the file (for error messages).  */
  262.  
  263. void
  264. mywrite (desc, buf, bytes, file)
  265.      int desc;
  266.      char *buf;
  267.      int bytes;
  268.      char *file;
  269. {
  270.   register int val;
  271.  
  272.   while (bytes > 0)
  273.     {
  274.       val = write (desc, buf, bytes);
  275.       if (val <= 0)
  276.     perror_with_name (file);
  277.       buf += val;
  278.       bytes -= val;
  279.     }
  280. }
  281.  
  282. int
  283. main (argc, argv)
  284.      int argc;
  285.      char **argv;
  286. {
  287.   int i;
  288.  
  289.   operation = 0;
  290.   verbose = 0;
  291.   newer_only = 0;
  292.   silent_create = 0;
  293.   posname = 0;
  294.   postype = POS_DEFAULT;
  295.   preserve_dates = 0;
  296.   symdef_flag = 0;
  297.   symdef_exists = 0;
  298.   ignore_symdef = 0;
  299.   symdef_mapelt = 0;
  300.   files = 0;
  301.   lock_indesc = -1;
  302.  
  303.   if (argc < 2)
  304.     usage ("too few command arguments", 0);
  305.  
  306.   {
  307.     char *key = argv[1];
  308.     char *p = key;
  309.     char c;
  310.  
  311.     while (c = *p++)
  312.       {
  313.     switch (c)
  314.       {
  315.       case 'a':
  316.         postype = POS_AFTER;
  317.         break;
  318.  
  319.       case 'b':
  320.         postype = POS_BEFORE;
  321.         break;
  322.  
  323.       case 'c':
  324.         silent_create = 1;
  325.         break;
  326.  
  327.       case 'd':
  328.         if (operation)
  329.           two_operations ();
  330.  
  331.         operation = DELETE;
  332.         break;
  333.  
  334.       case 'i':
  335.         postype = POS_BEFORE;
  336.         break;
  337.  
  338.       case 'l':
  339.         break;
  340.  
  341.       case 'm':
  342.         if (operation)
  343.           two_operations ();
  344.         operation = MOVE;
  345.         break;
  346.  
  347.       case 'o':
  348.         preserve_dates = 1;
  349.         break;
  350.  
  351.       case 'p':
  352.         if (operation)
  353.           two_operations ();
  354.         operation = PRINT_FILES;
  355.         break;
  356.  
  357.       case 'q':
  358.         if (operation)
  359.           two_operations ();
  360.         operation = QUICK_APPEND;
  361.         break;
  362.  
  363.       case 'r':
  364.         if (operation)
  365.           two_operations ();
  366.         operation = REPLACE;
  367.         break;
  368.  
  369.       case 's':
  370.         symdef_flag = 1;
  371.         break;
  372.  
  373.       case 't':
  374.         if (operation)
  375.           two_operations ();
  376.         operation = PRINT_TABLE;
  377.         break;
  378.  
  379.       case 'u':
  380.         operation = REPLACE;
  381.         newer_only = 1;
  382.         break;
  383.  
  384.       case 'v':
  385.         verbose = 1;
  386.         break;
  387.  
  388.       case 'x':
  389.         if (operation)
  390.           two_operations ();
  391.         operation = EXTRACT;
  392.         break;
  393.       }
  394.       }
  395.   
  396.   }
  397.  
  398.   if (operation == 0 && symdef_flag)
  399.     operation = REPLACE;
  400.  
  401.   if (operation == 0)
  402.     usage ("no operation specified", 0);
  403.  
  404.   i = 2;
  405.  
  406.   if (postype != POS_DEFAULT)
  407.     posname = argv[i++];
  408.  
  409.   archive = argv[i++];
  410.  
  411.   if (i < argc)
  412.     {
  413.       files = &argv[i];
  414.       while (i < argc)
  415.     if (!strcmp (argv[i++], "__.SYMDEF"))
  416.       {
  417.         ignore_symdef = 1;
  418.         break;
  419.       }
  420.     }
  421.  
  422.   switch (operation)
  423.     {
  424.     case EXTRACT:
  425.     extract_members (extract_member);
  426.     break;
  427.  
  428.     case PRINT_TABLE:
  429.     extract_members (print_descr);
  430.     break;
  431.  
  432.     case PRINT_FILES:
  433.     extract_members (print_contents);
  434.     break;
  435.  
  436.     case DELETE:
  437.     if (files != 0)
  438.       delete_members ();
  439.     break;
  440.  
  441.     case MOVE:
  442.     if (files != 0)
  443.       move_members ();
  444.     break;
  445.  
  446.     case REPLACE:
  447.     if (files != 0 || symdef_flag)
  448.       replace_members ();
  449.     break;
  450.  
  451.     case QUICK_APPEND:
  452.     if (files != 0)
  453.       quick_append ();
  454.     break;
  455.  
  456.     default:
  457.     usage ("invalid operation %d", operation);
  458.     }
  459.  
  460.   exit (0);
  461.   return 0;
  462. }
  463.  
  464. void
  465. two_operations ()
  466. {
  467.   usage ("two different operation switches specified", 0);
  468. }
  469.  
  470. void
  471. scan (function, crflag)
  472.      void (*function) ();
  473.      int crflag;
  474. {
  475.   FILE *arcstream = fopen (archive, "r");
  476.  
  477.   if (arcstream == 0 && crflag)
  478.     /* Creation-warning, if desired, will happen later.  */
  479.     return;
  480.  
  481.   if (arcstream == 0)
  482.     {
  483.       perror_with_name (archive);
  484.       exit (1);
  485.     }
  486.   {
  487.     char buf[SARMAG];
  488.     int nread = fread (buf, 1, SARMAG, arcstream);
  489.     if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
  490.       fatal ("file %s not a valid archive", archive);
  491.   }
  492.  
  493.   /* Now find the members one by one.  */
  494.   {
  495.     int member_offset = SARMAG;
  496.     while (1)
  497.       {
  498.     int nread;
  499.     struct ar_hdr member_header;
  500.     struct member_desc member_desc;
  501.     char name [1 + sizeof member_header.ar_name];
  502.  
  503.     if (fseek (arcstream, member_offset, 0) < 0)
  504.       perror_with_name (archive);
  505.  
  506.     nread = fread (&member_header, 1, sizeof (struct ar_hdr), arcstream);
  507.     if (nread == 0)
  508.       /* No data left means end of file; that is OK.  */
  509.       break;
  510.  
  511.     if (nread != sizeof (member_header)
  512.         || bcmp (member_header.ar_fmag, ARFMAG, 2))
  513.       fatal ("file %s not a valid archive", archive);
  514.     bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
  515.     {
  516.       char *p = name + sizeof member_header.ar_name;
  517.       *p = '\0';
  518.       while (p > name && *--p == ' ')
  519.         *p = '\0';
  520.     }
  521.     member_desc.name = name;
  522.     sscanf (member_header.ar_mode, "%o", &member_desc.mode);
  523.     member_desc.date = atoi (member_header.ar_date);
  524.     member_desc.size = atoi (member_header.ar_size);
  525.     member_desc.uid = atoi (member_header.ar_uid);
  526.     member_desc.gid = atoi (member_header.ar_gid);
  527.     member_desc.offset = member_offset;
  528.     member_desc.data_offset = member_offset + sizeof (member_header);
  529.  
  530.     member_desc.new_offset = 0;
  531.     member_desc.symdefs = 0;
  532.     member_desc.nsymdefs = 0;
  533.     member_desc.string_size = 0;
  534.  
  535.     if (!ignore_symdef && !strcmp (name, "__.SYMDEF"))
  536.       symdef_exists = 1;
  537.  
  538.     function (member_desc, arcstream);
  539.  
  540.     member_offset += sizeof (member_header) + member_desc.size;
  541.     if (member_offset & 1)
  542.       ++member_offset;
  543.       }
  544.   }
  545.  
  546.   
  547.   fclose (arcstream);
  548. }
  549.  
  550. void print_modes ();
  551.  
  552. void
  553. print_descr (member)
  554.      struct member_desc member;
  555. {
  556.   char *timestring;
  557.   if (!verbose)
  558.     {
  559.       puts (member.name);
  560.       return;
  561.     }
  562.   print_modes (member.mode);
  563.   timestring = ctime (&member.date);
  564.   printf (" %2d/%2d %6d %12.12s %4.4s %s\n",
  565.       member.uid, member.gid,
  566.       member.size, timestring + 4, timestring + 20,
  567.       member.name);
  568. }
  569.  
  570. void
  571. print_modes (modes)
  572.      int modes;
  573. {
  574.   putchar (modes & 0400 ? 'r' : '-');
  575.   putchar (modes & 0200 ? 'w' : '-');
  576.   putchar (modes & 0100 ? 'x' : '-');
  577.   putchar (modes & 040 ? 'r' : '-');
  578.   putchar (modes & 020 ? 'w' : '-');
  579.   putchar (modes & 010 ? 'x' : '-');
  580.   putchar (modes & 04 ? 'r' : '-');
  581.   putchar (modes & 02 ? 'w' : '-');
  582.   putchar (modes & 01 ? 'x' : '-');
  583. }
  584.  
  585. #define BUFSIZE 1024
  586.  
  587. void
  588. extract_member (member, istream)
  589.      struct member_desc member;
  590.      FILE *istream;
  591. {
  592.   int ncopied = 0;
  593.   FILE *ostream;
  594.  
  595.   fseek (istream, member.data_offset, 0);
  596.   ostream = fopen (member.name, "w");
  597.   if (!ostream)
  598.     {
  599.       perror_with_name (member.name);
  600.       return;
  601.     }
  602.  
  603.   if (verbose)
  604.     printf ("x - %s\n", member.name);
  605.  
  606.   while (ncopied < member.size)
  607.     {
  608.       char buf [BUFSIZE];
  609.       int tocopy = member.size - ncopied;
  610.       int nread;
  611.       if (tocopy > BUFSIZE) tocopy = BUFSIZE;
  612.       nread = fread (buf, 1, tocopy, istream);
  613.       if (nread != tocopy)
  614.     fatal ("file %s not a valid archive", archive);
  615.       fwrite (buf, 1, nread, ostream);
  616.       ncopied += tocopy;
  617.     }
  618.  
  619. #ifdef USG
  620.   chmod (member.name, member.mode);
  621. #else
  622.   fchmod (fileno (ostream), member.mode);
  623. #endif
  624.   if (ferror (ostream) || fclose (ostream) != 0)
  625.     error ("%s: I/O error", member.name);
  626.  
  627.   if (preserve_dates)
  628.     {
  629. #ifdef USG
  630.       long tv[2];
  631.       tv[0] = member.date;
  632.       tv[1] = member.date;
  633.       utime (member.name, tv);
  634. #else
  635.       struct timeval tv[2];
  636.       tv[0].tv_sec = member.date;
  637.       tv[0].tv_usec = 0;
  638.       tv[1].tv_sec = member.date;
  639.       tv[1].tv_usec = 0;
  640.       utimes (member.name, tv);
  641. #endif
  642.     }
  643. }
  644.  
  645. void
  646. print_contents (member, istream)
  647.      struct member_desc member;
  648.      FILE *istream;
  649. {
  650.   int ncopied = 0;
  651.  
  652.   fseek (istream, member.data_offset, 0);
  653.  
  654.   if (verbose)
  655.   printf ("\n<member %s>\n\n", member.name);
  656.  
  657.   while (ncopied < member.size)
  658.     {
  659.       char buf [BUFSIZE];
  660.       int tocopy = member.size - ncopied;
  661.       int nread;
  662.       if (tocopy > BUFSIZE) tocopy = BUFSIZE;
  663.       nread = fread (buf, 1, tocopy, istream);
  664.       if (nread != tocopy)
  665.     fatal ("file %s not a valid archive", archive);
  666.       fwrite (buf, 1, nread, stdout);
  667.       ncopied += tocopy;
  668.     }
  669. }
  670.  
  671. /* Make a map of the existing members of the archive: their names,
  672.  positions and sizes.  */
  673.  
  674. /* If `nonexistent_ok' is nonzero,
  675.  just return 0 for an archive that does not exist.
  676.  This will cause the ordinary supersede procedure to
  677.  create a new archive.  */
  678.  
  679. struct mapelt *
  680. make_map (nonexistent_ok)
  681.      int nonexistent_ok;
  682. {
  683.   struct mapelt mapstart;
  684.   mapstart.next = 0;
  685.   maplast = &mapstart;
  686.   scan (add_to_map, nonexistent_ok);
  687.   return mapstart.next;
  688. }
  689.  
  690. void
  691. add_to_map (member)
  692.      struct member_desc member;
  693. {
  694.   struct mapelt *mapelt = (struct mapelt *) xmalloc (sizeof (struct mapelt));
  695.   mapelt->info = member;
  696.   mapelt->info.name = concat (mapelt->info.name, "", "");
  697.   maplast->next = mapelt;
  698.   mapelt->next = 0;
  699.   maplast = mapelt;
  700. }
  701.  
  702. /* Return the last element of the specified map.  */
  703.  
  704. struct mapelt *
  705. last_mapelt (map)
  706.      struct mapelt *map;
  707. {
  708.   struct mapelt *tail = map;
  709.   while (tail->next) tail = tail->next;
  710.   return tail;
  711. }
  712.  
  713. /* Return the element of the specified map which precedes elt.  */
  714.  
  715. struct mapelt *
  716. prev_mapelt (map, elt)
  717.      struct mapelt *map, *elt;
  718. {
  719.   struct mapelt *tail = map;
  720.   while (tail->next && tail->next != elt)
  721.     tail = tail->next;
  722.   if (tail->next) return tail;
  723.   return 0;
  724. }
  725.  
  726. /* Return the element of the specified map which has the specified name.  */
  727.  
  728. struct mapelt *
  729. find_mapelt_noerror (map, name)
  730.      struct mapelt *map;
  731.      register char *name;
  732. {
  733.   register struct mapelt *tail;
  734.   unsigned int len = strlen (name);
  735.   int dot_o = name[len - 2] == '.' && name[len - 1] == 'o';
  736.  
  737.   for (tail = map; tail != 0; tail = tail->next)
  738.     {
  739.       if (tail->info.name == 0)
  740.     continue;
  741.       if (!strncmp (tail->info.name, name, 13))
  742.     {
  743.       unsigned int eltlen = strlen (tail->info.name);
  744.       if (len <= 13 || eltlen <= 13)
  745.         return tail;
  746.       else
  747.         {
  748.           char *p = tail->info.name + 13;
  749.           if (dot_o && p[0] == '.' && p[1] == 'o' && p[2] == '\0')
  750.         return tail;
  751.           else if (!strncmp (p, name + 13,
  752.                  (len > eltlen ? len : eltlen) - 13))
  753.         return tail;
  754.         }
  755.     }
  756.     }
  757.  
  758.   return 0;
  759. }
  760.  
  761. struct mapelt *
  762. find_mapelt (map, name)
  763.      struct mapelt *map;
  764.      char *name;
  765. {
  766.   register struct mapelt *found = find_mapelt_noerror (map, name);
  767.   if (found == 0)
  768.     error ("no member named `%s'", name);
  769.   return found;
  770. }
  771.  
  772. /* Before looking at the archive, if we are going to update it
  773.    based on looking at its current contents, make an exclusive lock on it.
  774.    The lock is released when `write_archive' is called.  */
  775.  
  776. void
  777. lock_for_update ()
  778. {
  779.   /* Open the existing archive file; if that fails, create an empty one.  */
  780.  
  781.   lock_indesc = open (archive, O_RDWR, 0);
  782.  
  783.   if (lock_indesc < 0)
  784.     {
  785.       int outdesc;
  786.  
  787.       if (!silent_create)
  788.     printf ("Creating archive file `%s'\n", archive);
  789.       outdesc = open (archive, O_WRONLY | O_APPEND | O_CREAT, 0666);
  790.       if (outdesc < 0)
  791.     pfatal_with_name (archive);
  792.       mywrite (outdesc, ARMAG, SARMAG, archive);
  793.       close (outdesc);
  794.  
  795.       /* Now we had better be able to open for update!  */
  796.  
  797.       lock_indesc = open (archive, O_RDWR, 0);
  798.       if (lock_indesc < 0)
  799.     pfatal_with_name (archive);
  800.     }
  801.  
  802. #ifdef LOCKS
  803.   /* Lock the old file so that it won't be updated by two programs at once.
  804.      This uses the fcntl locking facility found on Sun systems
  805.      which is also in POSIX.  (Perhaps it comes from sysV.)
  806.  
  807.      Note that merely reading an archive does not require a lock,
  808.      because we use `rename' to update the whole file atomically.  */
  809.  
  810.   {
  811.     struct flock lock;
  812.  
  813.     lock.l_type = F_WRLCK;
  814.     lock.l_whence = 0;
  815.     lock.l_start = 0;
  816.     lock.l_len = 0;
  817.  
  818.     while (1)
  819.       {
  820.     int value = fcntl (lock_indesc, F_SETLKW, &lock);
  821.     if (value >= 0)
  822.       break;
  823.     else if (errno == EINTR)
  824.       continue;
  825.     else
  826.       pfatal_with_name ("locking archive");
  827.       }
  828.   }
  829. #endif
  830. }
  831.  
  832. /* Unlock archive and close the file descriptor.  */
  833.  
  834. void
  835. close_archive ()
  836. {
  837. #ifdef LOCKS
  838.   {
  839.     struct flock lock;
  840.  
  841.     /* Unlock the old archive.  */
  842.  
  843.     lock.l_type = F_UNLCK;
  844.     lock.l_whence = 0;
  845.     lock.l_start = 0;
  846.     lock.l_len = 0;
  847.  
  848.     fcntl (lock_indesc, F_SETLK, &lock);
  849.   }
  850. #endif
  851.  
  852.   /* Close the archive.  If we renamed a new one, the old one disappears.  */
  853.   close (lock_indesc);
  854. }
  855.  
  856. /* Write a new archive file from a given map.  */
  857. /* When a map is used as the pattern for a new archive,
  858.  each element represents one member to put in it, and
  859.  the order of elements controls the order of writing.
  860.  
  861.  Ordinarily, the element describes a member of the old
  862.  archive, to be copied into the new one.
  863.  
  864.  If the `offset' field of the element's info is 0,
  865.  then the element describes a file to be copied into the
  866.  new archive.  The `name' field is the file's name.
  867.  
  868.  If the `name' field of an element is 0, the element is ignored.
  869.  This makes it easy to specify deletion of archive members.
  870.  
  871.  Every operation that will eventually call `write_archive'
  872.  should call `lock_for_update' before beginning
  873.  to do any I/O on the archive file.
  874. */
  875.  
  876. char *make_tempname ();
  877. void copy_out_member ();
  878.  
  879. void
  880. write_archive (map, appendflag)
  881.      struct mapelt *map;
  882.      int appendflag;
  883. {
  884.   char *tempname = make_tempname (archive);
  885.   int indesc = lock_indesc;
  886.   int outdesc;
  887.   char *outname;
  888.   struct mapelt *tail;
  889.  
  890.   /* Now open the output.  */
  891.  
  892.   if (!appendflag)
  893.     {
  894.       /* Updating an existing archive normally.
  895.      Write output as TEMPNAME and rename at the end.
  896.      There can never be two invocations trying to do this at once,
  897.      because of the lock made on the old archive file.  */
  898.  
  899.       outdesc = open (tempname, O_WRONLY | O_CREAT, 0666);
  900.       if (outdesc < 0)
  901.     pfatal_with_name (tempname);
  902.       outname = tempname;
  903.       mywrite (outdesc, ARMAG, SARMAG, outname);
  904.     }
  905.   else
  906.     {
  907.       /* Fast-append to existing archive.  */
  908.  
  909.       outdesc = open (archive, O_WRONLY | O_APPEND, 0);
  910.       if (outdesc < 0)
  911.     pfatal_with_name (archive);
  912.       outname = archive;
  913.     }
  914.  
  915.   /* If archive has or should have a __.SYMDEF member,
  916.      compute the contents for it.  */
  917.  
  918.   if (symdef_flag || symdef_exists)
  919.     {
  920.       if (symdef_exists)
  921.     read_old_symdefs (map, indesc);
  922.       else
  923.     {
  924.       struct mapelt *this = (struct mapelt *)
  925.         xmalloc (sizeof (struct mapelt));
  926.       this->info.name = "__.SYMDEF";
  927.       this->info.offset = SARMAG;
  928.       this->info.data_offset = SARMAG + sizeof (struct ar_hdr);
  929.       this->info.new_offset = 0;
  930.       this->info.date = 0;
  931.       this->info.size = 0;
  932.       this->info.uid = 0;
  933.       this->info.gid = 0;
  934.       this->info.mode = 0666;
  935.       this->info.symdefs = 0;
  936.       this->info.nsymdefs = 0;
  937.       this->info.string_size = 0;
  938.       this->next = map;
  939.       map = this;
  940.       original_num_symdefs = 0;
  941.       old_strings_size = 0;
  942.     }
  943.  
  944.       update_symdefs (map, indesc);
  945.     }
  946.  
  947.   /* Copy the members into the output, either from the old archive
  948.      or from specified files.  */
  949.  
  950.   for (tail = map; tail != 0; tail = tail->next)
  951.     {
  952.       if ((symdef_flag || symdef_exists) && tail->info.name
  953.       && !strcmp (tail->info.name, "__.SYMDEF")
  954. #if 0
  955.       && tail->info.date==0
  956. #endif
  957.       )
  958.     write_symdef_member (tail, map, outdesc, outname);
  959.       else
  960.     copy_out_member (tail, indesc, outdesc, outname);
  961.     }
  962.  
  963.   if (symdef_mapelt != 0)
  964.     {
  965.       /* Check for members whose data offsets weren't
  966.      known when the symdef member was first written.  */
  967.       int doneany = 0;
  968.       for (tail = map; tail != 0; tail = tail->next)
  969.     if (tail->info.offset == 0)
  970.       {
  971.         /* Fix up the symdefs.  */
  972.         register unsigned int i;
  973.         for (i = 0; i < tail->info.nsymdefs; ++i)
  974.           tail->info.symdefs[i].offset = tail->info.new_offset;
  975.         doneany = 1;
  976.       }
  977.       if (doneany)
  978.     {
  979.       /* Some files had bad symdefs; rewrite the symdef member.  */
  980.       lseek (outdesc, symdef_mapelt->info.offset, 0);
  981.       write_symdef_member (symdef_mapelt, map, outdesc, outname);
  982.     }
  983.     }
  984.  
  985.   /* Mark the __.SYMDEF member as up to date.  */
  986.  
  987.   if (symdef_mapelt != 0)
  988.     touch_symdef_member (outdesc, outname);
  989.  
  990.   /* Install the new output under the intended name.  */
  991.  
  992. #ifndef USG
  993.   fsync (outdesc);
  994. #endif
  995.   close (outdesc);
  996.  
  997. #ifndef MCH_AMIGA
  998.   if (!appendflag)
  999.     if (rename (tempname, archive))
  1000.       pfatal_with_name (tempname);
  1001.  
  1002.   close_archive ();
  1003. #else
  1004.   /* we *have* to close the file before we rename it, because otherwise
  1005.    * AmigaDOS will just abort with OBJECT_IN_USE_ERROR */
  1006.   close_archive ();
  1007.  
  1008.   if (!appendflag)
  1009.     if (rename (tempname, archive))
  1010.       pfatal_with_name (tempname);
  1011. #endif
  1012. }
  1013.  
  1014. void
  1015. header_from_map (header, mapelt)
  1016.      struct ar_hdr *header;
  1017.      struct mapelt *mapelt;
  1018. {
  1019.   unsigned int namelen;
  1020.  
  1021.   /* Zero the header, then store in the data as text.  */
  1022.   bzero ((char *) header, sizeof (*header));
  1023.  
  1024.   strncpy (header->ar_name, mapelt->info.name, sizeof (header->ar_name));
  1025.   namelen = strlen (mapelt->info.name);
  1026.   if (namelen >= sizeof (header->ar_name))
  1027.     {
  1028.       if (mapelt->info.name[namelen - 2] == '.' &&
  1029.       mapelt->info.name[namelen - 1] == 'o')
  1030.     {
  1031.       header->ar_name[sizeof (header->ar_name) - 3] = '.';
  1032.       header->ar_name[sizeof (header->ar_name) - 2] = 'o';
  1033.     }
  1034.       header->ar_name[sizeof (header->ar_name) - 1] = '\0';
  1035.       error ("member name `%s' truncated to `%s'",
  1036.          mapelt->info.name, header->ar_name);
  1037.     }
  1038.  
  1039.   sprintf (header->ar_date, "%ld", mapelt->info.date);
  1040.   sprintf (header->ar_size, "%d", mapelt->info.size);
  1041.   sprintf (header->ar_uid, "%d", mapelt->info.uid);
  1042.   sprintf (header->ar_gid, "%d", mapelt->info.gid);
  1043.   sprintf (header->ar_mode, "%o", mapelt->info.mode);
  1044.   strncpy (header->ar_fmag, ARFMAG, sizeof (header->ar_fmag));
  1045.  
  1046.   /* Change all remaining nulls in the header into spaces.  */
  1047.   {
  1048.     char *end = (char *) &header[1];
  1049.     register char *p;
  1050.     for (p = (char *) header; p < end; ++p)
  1051.       if (*p == '\0')
  1052.     *p = ' ';
  1053.   }
  1054. }
  1055.  
  1056. /* writes to file open on OUTDESC with name OUTNAME.  */
  1057. void
  1058. copy_out_member (mapelt, archive_indesc, outdesc, outname)
  1059.      struct mapelt *mapelt;
  1060.      int archive_indesc;
  1061.      int outdesc;
  1062. {
  1063.   struct ar_hdr header;
  1064.   int indesc;
  1065.  
  1066.   if (mapelt->info.name == 0)
  1067.     /* This element was cancelled.  */
  1068.     return;
  1069.  
  1070.   header_from_map (&header, mapelt);
  1071.  
  1072.   if (mapelt->info.offset != 0)
  1073.     {
  1074.       indesc = archive_indesc;
  1075.       lseek (indesc, mapelt->info.data_offset, 0);
  1076.     }
  1077.   else
  1078.     {
  1079.       indesc = open (mapelt->info.name, 0, 0);
  1080.       if (indesc < 0)
  1081.     {
  1082.       perror_with_name (mapelt->info.name);
  1083.       return;
  1084.     }
  1085.     }
  1086.  
  1087.   mywrite (outdesc, &header, sizeof (header), outname);
  1088.  
  1089.   if (mapelt->info.data_offset == 0)
  1090.     mapelt->info.data_offset = lseek (outdesc, 0L, 1);
  1091.  
  1092.   {
  1093.     char buf[BUFSIZE];
  1094.     int tocopy = mapelt->info.size;
  1095.     while (tocopy > 0)
  1096.       {
  1097.     int thistime = tocopy;
  1098.     if (thistime > BUFSIZE) thistime = BUFSIZE;
  1099.         read (indesc, buf, thistime);
  1100.     mywrite (outdesc, buf, thistime, outname);
  1101.     tocopy -= thistime;
  1102.       }
  1103.   }
  1104.  
  1105.   if (indesc != archive_indesc)
  1106.     close (indesc);
  1107.  
  1108.   if (mapelt->info.size & 1)
  1109.     mywrite (outdesc, "\n", 1, outname);
  1110. }
  1111.  
  1112. /* Update the time of the __.SYMDEF member; done when we updated
  1113.    that member, just before we close the new archive file.
  1114.    It is open on OUTDESC and its name is OUTNAME.  */
  1115.  
  1116. void
  1117. touch_symdef_member (outdesc, outname)
  1118.      int outdesc;
  1119.      char *outname;
  1120. {
  1121.   struct stat statbuf;
  1122.   int i;
  1123.  
  1124.   /* See what mtime the archive file has as a result of our writing it.  */
  1125.   fstat (outdesc, &statbuf);
  1126.  
  1127.   /* Advance member's time to that time.  */
  1128.   bzero (symdef_header.ar_date, sizeof symdef_header.ar_date);
  1129.   sprintf (symdef_header.ar_date, "%ld", statbuf.st_mtime);
  1130.   for (i = 0; i < sizeof symdef_header.ar_date; i++)
  1131.     if (symdef_header.ar_date[i] == 0)
  1132.       symdef_header.ar_date[i] = ' ';
  1133.  
  1134.   /* Write back this member's header with the new time.  */
  1135.   if (lseek (outdesc, symdef_mapelt->info.new_offset, 0) >= 0)
  1136.     mywrite (outdesc, &symdef_header, sizeof symdef_header, outname);
  1137. }
  1138.  
  1139. char *
  1140. make_tempname (name)
  1141.      char *name;
  1142. {
  1143.   return concat (name, "", "_supersede");
  1144. }
  1145.  
  1146. void
  1147. delete_members ()
  1148. {
  1149.   struct mapelt *map = make_map (0);
  1150.   struct mapelt *tail;
  1151.   struct mapelt mapstart;
  1152.   char **p;
  1153.  
  1154.   mapstart.info.name = 0;
  1155.   mapstart.next = map;
  1156.   map = &mapstart;
  1157.  
  1158.   lock_for_update ();
  1159.  
  1160.   if (files)
  1161.     for (p = files; *p; p++)
  1162.       {
  1163.     /* If user says to delete the __.SYMDEF member,
  1164.        don't make a new one to replace it.  */
  1165.     if (!strcmp (*p, "__.SYMDEF"))
  1166.       symdef_exists = 0;
  1167.     delete_from_map (*p, map);
  1168.       }
  1169.  
  1170.   write_archive (map->next, 0);
  1171. }
  1172.  
  1173. void
  1174. delete_from_map (name, map)
  1175.      char *name;
  1176.      struct mapelt *map;
  1177. {
  1178.   struct mapelt *this = find_mapelt (map, name);
  1179.  
  1180.   if (!this) return;
  1181.   this->info.name = 0;
  1182.   if (verbose)
  1183.     printf ("d - %s\n", name);
  1184. }
  1185.  
  1186. void
  1187. move_members ()
  1188. {
  1189.   struct mapelt *map = make_map (0);
  1190.   char **p;
  1191.   struct mapelt *after_mapelt;
  1192.   struct mapelt mapstart;
  1193.   struct mapelt *change_map;
  1194.  
  1195.   mapstart.info.name = 0;
  1196.   mapstart.next = map;
  1197.   change_map = &mapstart;
  1198.  
  1199.   lock_for_update ();
  1200.  
  1201.   switch (postype)
  1202.     {
  1203.     case POS_DEFAULT:
  1204.       after_mapelt = last_mapelt (change_map);
  1205.       break;
  1206.  
  1207.     case POS_AFTER:
  1208.       after_mapelt = find_mapelt (map, posname);
  1209.       break;
  1210.  
  1211.     case POS_BEFORE:
  1212.       after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
  1213.     }
  1214.  
  1215.   /* Failure to find specified "before" or "after" member
  1216.      is a fatal error; message has already been printed.  */
  1217.  
  1218.   if (!after_mapelt) exit (1);
  1219.  
  1220.   if (files)
  1221.     for (p = files; *p; p++)
  1222.       {
  1223.     if (move_in_map (*p, change_map, after_mapelt))
  1224.       after_mapelt = after_mapelt->next;
  1225.       }
  1226.  
  1227.   write_archive (map, 0);
  1228. }
  1229.  
  1230. int
  1231. move_in_map (name, map, after)
  1232.      char *name;
  1233.      struct mapelt *map, *after;
  1234. {
  1235.   struct mapelt *this = find_mapelt (map, name);
  1236.   struct mapelt *prev;
  1237.  
  1238.   if (!this) return 0;
  1239.   prev = prev_mapelt (map, this);
  1240.   prev->next = this->next;
  1241.   this->next = after->next;
  1242.   after->next = this;
  1243.   return 1;
  1244. }
  1245.  
  1246. /* Insert files into the archive.  */
  1247.  
  1248. void
  1249. replace_members ()
  1250. {
  1251.   struct mapelt *map = make_map (1);
  1252.   struct mapelt mapstart;
  1253.   struct mapelt *after_mapelt;
  1254.   struct mapelt *change_map;
  1255.   char **p;
  1256.   int changed;
  1257.  
  1258.   mapstart.info.name = 0;
  1259.   mapstart.next = map;
  1260.   change_map = &mapstart;
  1261.  
  1262.   lock_for_update ();
  1263.  
  1264.   switch (postype)
  1265.     {
  1266.     case POS_DEFAULT:
  1267.       after_mapelt = last_mapelt (change_map);
  1268.       break;
  1269.  
  1270.     case POS_AFTER:
  1271.       after_mapelt = find_mapelt (map, posname);
  1272.       break;
  1273.  
  1274.     case POS_BEFORE:
  1275.       after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
  1276.     }
  1277.  
  1278.   /* Failure to find specified "before" or "after" member
  1279.      is a fatal error; the message has already been printed.  */
  1280.   if (after_mapelt == 0)
  1281.     exit (1);
  1282.  
  1283.   changed = 0;
  1284.   if (files != 0)
  1285.     for (p = files; *p != 0; ++p)
  1286.       if (insert_in_map (*p, change_map, after_mapelt))
  1287.     {
  1288.       after_mapelt = after_mapelt->next;
  1289.       changed = 1;
  1290.     }
  1291.  
  1292.   change_map = change_map->next;
  1293.   if (!changed && (!symdef_flag || symdef_exists))
  1294.     /* Nothing changed.  */
  1295.     close_archive (change_map);
  1296.   else
  1297.     write_archive (change_map, 0);
  1298. }
  1299.  
  1300. /* Handle the "quick insert" operation.  */
  1301.  
  1302. void
  1303. quick_append ()
  1304. {
  1305.   struct mapelt *map;
  1306.   struct mapelt *after;
  1307.   struct mapelt mapstart;
  1308.   char **p;
  1309.  
  1310.   mapstart.info.name = 0;
  1311.   mapstart.next = 0;
  1312.   map = &mapstart;
  1313.   after = map;
  1314.  
  1315.   lock_for_update ();
  1316.  
  1317.   /* Insert the specified files into the "map",
  1318.      but is a map of the inserted files only,
  1319.      and starts out empty.  */
  1320.   if (files)
  1321.     for (p = files; *p; p++)
  1322.       {
  1323.     if (insert_in_map (*p, map, after))
  1324.       after = after->next;
  1325.       }
  1326.  
  1327.   /* Append these files to the end of the existing archive file.  */
  1328.  
  1329.   write_archive (map->next, 1);
  1330. }
  1331.  
  1332. /* Insert an entry for name NAME into the map MAP after the map entry AFTER.
  1333.    Delete an old entry for NAME.
  1334.    MAP is assumed to start with a dummy entry, which facilitates
  1335.    insertion at the beginning of the list.
  1336.    Return 1 if successful, 0 if did nothing because file NAME doesn't
  1337.    exist or (optionally) is older.  */
  1338.  
  1339. int
  1340. insert_in_map (name, map, after)
  1341.      char *name;
  1342.      struct mapelt *map, *after;
  1343. {
  1344.   struct mapelt *old = find_mapelt_noerror (map, name);
  1345.   struct mapelt *this;
  1346.   struct stat status;
  1347.  
  1348.   if (stat (name, &status))
  1349.     {
  1350.       perror_with_name (name);
  1351.       return 0;
  1352.     }
  1353.   if (old && newer_only && status.st_mtime <= old->info.date)
  1354.     return 0;
  1355.   if (old)
  1356.     /* Delete the old one.  */
  1357.     old->info.name = 0;
  1358.   this = (struct mapelt *) xmalloc (sizeof (struct mapelt));
  1359.   this->info.name = name;
  1360.   this->info.offset = 0;
  1361.   this->info.data_offset = 0;
  1362.   this->info.date = status.st_mtime;
  1363.   this->info.size = status.st_size;
  1364.   this->info.uid = status.st_uid;
  1365.   this->info.gid = status.st_gid;
  1366.   this->info.mode = status.st_mode;
  1367.   this->next = after->next;
  1368.   after->next = this;
  1369.  
  1370.   if (verbose)
  1371.     printf ("%c - %s\n", old == 0 ? 'a' : 'r', this->info.name);
  1372.  
  1373.   return 1;
  1374. }
  1375.  
  1376. /* Apply a function to each of the specified members.
  1377. */
  1378.  
  1379. void
  1380. extract_members (function)
  1381.      void (*function) ();
  1382. {
  1383.   struct mapelt *map;
  1384.   FILE *arcstream;
  1385.   char **p;
  1386.  
  1387.   if (!files)
  1388.     {
  1389.       /* Handle case where we want to operate on every member.
  1390.      No need to make a map and search it for this.  */
  1391.       scan (function, 0);
  1392.       return;
  1393.     }
  1394.  
  1395.   arcstream = fopen (archive, "r");
  1396.   if (!arcstream)
  1397.     fatal ("failure opening archive %s for the second time", archive);
  1398.   map = make_map (0);
  1399.  
  1400.   for (p = files; *p; p++)
  1401.     {
  1402.       struct mapelt *this = find_mapelt (map, *p);
  1403.       if (!this) continue;
  1404.       function (this->info, arcstream);
  1405.     }
  1406.  
  1407.   fclose (arcstream);
  1408. }
  1409.  
  1410. /* Write the __.SYMDEF member from data in core.  OUTDESC and OUTNAME
  1411.    are descriptor and name of file to write to.  */
  1412.  
  1413. void
  1414. write_symdef_member (mapelt, map, outdesc, outname)
  1415.      struct mapelt *mapelt;
  1416.      struct mapelt *map;
  1417.      int outdesc;
  1418.      char *outname;
  1419. {
  1420.   struct ar_hdr header;
  1421.   int indesc;
  1422.   struct mapelt *mapptr;
  1423.   unsigned long int symdefs_size;
  1424.  
  1425.   if (mapelt->info.name == 0)
  1426.     /* This element was cancelled.  */
  1427.     return;
  1428.  
  1429.   header_from_map (&header, mapelt);
  1430.  
  1431.   bcopy (&header, &symdef_header, sizeof header);
  1432.  
  1433.   mywrite (outdesc, &header, sizeof (header), outname);
  1434.  
  1435.   /* Write the number of symdefs.  */
  1436.   symdefs_size = nsymdefs * sizeof (struct symdef);
  1437.   mywrite (outdesc, &symdefs_size, sizeof symdefs_size, outname);
  1438.  
  1439.   /* Write symdefs surviving from old archive.  */
  1440.   mywrite (outdesc, old_symdefs, num_old_symdefs * sizeof (struct symdef),
  1441.        outname);
  1442.  
  1443.   /* Write symdefs for new members.  */
  1444.   for (mapptr = map; mapptr != 0; mapptr = mapptr->next)
  1445.     if (mapptr->info.nsymdefs != 0)
  1446.       write (outdesc, mapptr->info.symdefs,
  1447.          mapptr->info.nsymdefs * sizeof (struct symdef));
  1448.  
  1449.   /* Write the string table size.  */
  1450.   mywrite (outdesc, &new_strings_size, sizeof new_strings_size, outname);
  1451.  
  1452.   /* Write the string table.  */
  1453.   mywrite (outdesc, new_strings, new_strings_size, outname);
  1454.  
  1455.   if (mapelt->info.size & 1)
  1456.     mywrite (outdesc, "", 1, outname);
  1457. }
  1458.  
  1459. void
  1460. read_old_symdefs (map, archive_indesc)
  1461.      struct mapelt *map;
  1462.      int archive_indesc;
  1463. {
  1464.   struct mapelt *mapelt;
  1465.   char *data;
  1466.   int val;
  1467.   int symdefs_size;
  1468.  
  1469.   mapelt = find_mapelt_noerror (map, "__.SYMDEF");
  1470.   if (!mapelt)
  1471.     abort ();            /* Only call here if an old one exists */
  1472.  
  1473.   data  = (char *) xmalloc (mapelt->info.size);
  1474.   lseek (archive_indesc, mapelt->info.data_offset, 0);
  1475.   val = read (archive_indesc, data, mapelt->info.size);
  1476.  
  1477.   symdefs_size = *(unsigned long int *) data;
  1478.   original_num_symdefs = symdefs_size / sizeof (struct symdef);
  1479.   old_symdefs = (struct symdef *) (data + sizeof (symdefs_size));
  1480.   old_strings = ((char *) (old_symdefs + original_num_symdefs)
  1481.          + sizeof (symdefs_size));
  1482.   old_strings_size
  1483.     = *(unsigned long int *) (old_symdefs + original_num_symdefs);
  1484. }
  1485.  
  1486. /* Read various information from the header of an object file.
  1487.    Return 0 for failure or 1 for success.  */
  1488.  
  1489. int
  1490. read_header_info (mapelt, desc, offset, syms_offset, syms_size, strs_offset, strs_size)
  1491.      struct mapelt *mapelt;
  1492.      int desc;
  1493.      long int offset;
  1494.      long int *syms_offset;
  1495.      unsigned int *syms_size;
  1496.      long int *strs_offset;
  1497.      unsigned int *strs_size;
  1498. {
  1499. #ifdef A_OUT
  1500.   {
  1501.     struct exec hdr;
  1502.  
  1503.     lseek (desc, offset, 0);
  1504. #ifdef HEADER_SEEK_FD
  1505.     HEADER_SEEK_FD (desc);
  1506. #endif
  1507.  
  1508.     if (read (desc, (char *) &hdr, sizeof hdr) == sizeof hdr && !N_BADMAG(hdr))
  1509.       {
  1510.     *syms_offset = N_SYMOFF (hdr);
  1511.     *syms_size = hdr.a_syms;
  1512.     *strs_offset = N_STROFF (hdr);
  1513.     lseek (desc, N_STROFF (hdr) + offset, 0);
  1514.     if (read (desc, (char *) strs_size, sizeof *strs_size) != sizeof *strs_size)
  1515.       {
  1516.         error_with_file ("failure reading string table size in ", mapelt);
  1517.         return 0;
  1518.       }
  1519.     return 1;
  1520.       }
  1521.   }
  1522. #endif
  1523.  
  1524. #ifdef MACH_O
  1525.   {
  1526.     struct mach_header mach_header;
  1527.     struct load_command *load_command;
  1528.     struct symtab_command *symtab_command;
  1529.     char *hdrbuf;
  1530.     int cmd, symtab_seen;
  1531.  
  1532.     lseek (desc, offset, 0);
  1533.     if (read (desc, (char *) &mach_header, sizeof mach_header) == sizeof mach_header
  1534.     && mach_header.magic == MH_MAGIC)
  1535.       {
  1536.     hdrbuf = xmalloc (mach_header.sizeofcmds);
  1537.     if (read (desc, hdrbuf, mach_header.sizeofcmds) != mach_header.sizeofcmds)
  1538.       {
  1539.         error_with_file ("failure reading load commands of ", mapelt);
  1540.         return 0;
  1541.       }
  1542.     load_command = (struct load_command *) hdrbuf;
  1543.     symtab_seen = 0;
  1544.     for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
  1545.       {
  1546.         if (load_command->cmd == LC_SYMTAB)
  1547.           {
  1548.         symtab_seen = 1;
  1549.         symtab_command = (struct symtab_command *) load_command;
  1550.         *syms_offset = symtab_command->symoff;
  1551.         *syms_size = symtab_command->nsyms * sizeof (struct nlist);
  1552.         *strs_offset = symtab_command->stroff;
  1553.         *strs_size = symtab_command->strsize;
  1554.           }
  1555.         load_command = (struct load_command *) ((char *) load_command + load_command->cmdsize);
  1556.       }
  1557.     free (hdrbuf);
  1558.     if (!symtab_seen)
  1559.       *syms_offset = *syms_size = *strs_offset = *strs_size = 0;
  1560.     return 1;
  1561.       }
  1562.   }
  1563. #endif
  1564.  
  1565.   error_with_file ("bad format (not an object file) in ", mapelt);
  1566.   return 0;
  1567. }
  1568.  
  1569. /* Create the info.symdefs for a new member
  1570.    by reading the file it is coming from.  */
  1571.  
  1572. void
  1573. make_new_symdefs (mapelt, archive_indesc)
  1574.      struct mapelt *mapelt;
  1575.      int archive_indesc;
  1576. {
  1577.   int indesc;
  1578.   char *name = mapelt->info.name;
  1579.   long int syms_offset, strs_offset;
  1580.   unsigned int syms_size, strs_size;
  1581.   struct nlist *symbols;
  1582.   int symcount;
  1583.   char *strings;
  1584.   register unsigned int i;
  1585.   unsigned long int offset;
  1586.  
  1587.   if (name == 0)
  1588.     /* Deleted member.  */
  1589.     abort ();
  1590.  
  1591.   if (mapelt->info.offset != 0)
  1592.     {
  1593.       indesc = archive_indesc;
  1594.       lseek (indesc, mapelt->info.data_offset, 0);
  1595.       offset = mapelt->info.data_offset;
  1596.     }
  1597.   else
  1598.     {
  1599.       indesc = open (mapelt->info.name, 0, 0);
  1600.       if (indesc < 0)
  1601.     {
  1602.       perror_with_name (mapelt->info.name);
  1603.       return;
  1604.     }
  1605.       offset = 0;
  1606.     }
  1607.  
  1608.   if (!read_header_info (mapelt, indesc, offset, &syms_offset, &syms_size, &strs_offset, &strs_size))
  1609.     {
  1610.       if (mapelt->info.offset == 0)
  1611.     close (indesc);
  1612.       return;
  1613.     }
  1614.  
  1615.   /* Number of symbol entries in the file.  */
  1616.   symcount = syms_size / sizeof (struct nlist);
  1617.   /* Allocate temporary space for the symbol entries.  */
  1618.   symbols = (struct nlist *) alloca (syms_size);
  1619.   /* Read in the symbols.  */
  1620.   lseek (indesc, syms_offset + offset, 0);
  1621.   if (read (indesc, (char *) symbols, syms_size) != syms_size)
  1622.     {
  1623.       error_with_file ("premature end of file in symbols of ", mapelt);
  1624.       if (mapelt->info.offset == 0)
  1625.     (void) close (indesc);
  1626.       return;
  1627.     }
  1628.  
  1629.   /* The string table size includes the size word.  */
  1630.   if (strs_size < sizeof (strs_size))
  1631.     {
  1632.       error_with_file ("bad string table size in ", mapelt);
  1633.       if (mapelt->info.offset == 0)
  1634.     (void) close (indesc);
  1635.       return;
  1636.     }
  1637.   strs_size -= sizeof (strs_size);
  1638.  
  1639.   /* Allocate permanent space for the string table.  */
  1640.   strings = (char *) xmalloc (strs_size);
  1641.  
  1642.   /* Read in the strings.  */
  1643.   lseek (indesc, offset + strs_offset + sizeof strs_size, 0);
  1644.   if (read (indesc, strings, strs_size) != strs_size)
  1645.     {
  1646.       error_with_file ("premature end of file in strings of ", mapelt);
  1647.       if (mapelt->info.offset == 0)
  1648.     (void) close (indesc);
  1649.       return;
  1650.     }
  1651.  
  1652.   if (indesc != archive_indesc)
  1653.     (void) close (indesc);
  1654.  
  1655.   /* Discard the symbols we don't want to mention; compact the rest down.  */
  1656.   symcount = filter_symbols (symbols, symcount);
  1657.  
  1658.   mapelt->info.symdefs = (struct symdef *)
  1659.     xmalloc (symcount * sizeof (struct symdef));
  1660.   mapelt->info.nsymdefs = symcount;
  1661.   mapelt->info.string_size = 0;
  1662.  
  1663.   for (i = 0; i < symcount; ++i)
  1664.     {
  1665.       unsigned long int stroff = symbols[i].n_un.n_strx - sizeof (strs_size);
  1666.       char *symname = strings + stroff;
  1667.       if (stroff > strs_size)
  1668.     {
  1669.       char buf[100];
  1670.       sprintf (buf, "ridiculous string offset %lu in symbol %u of ",
  1671.            stroff + sizeof (strs_size), i);
  1672.       error_with_file (buf, mapelt);
  1673.       return;
  1674.     }
  1675.       mapelt->info.symdefs[i].s.name = symname;
  1676.       mapelt->info.string_size += strlen (symname) + 1;
  1677.     }
  1678. }
  1679.  
  1680. /* Choose which symbol entries to mention in __.SYMDEF;
  1681.    compact them downward to get rid of the rest.
  1682.    Return the number of symbols left.  */
  1683.  
  1684. int
  1685. filter_symbols (syms, symcount)
  1686.      struct nlist *syms;
  1687.      unsigned int symcount;
  1688. {
  1689.   struct nlist *from, *to;
  1690.   struct nlist *end = syms + symcount;
  1691.  
  1692.   for (to = from = syms; from < end; ++from)
  1693.     if ((from->n_type & N_EXT)
  1694.     && (from->n_type != N_EXT || from->n_value != 0))
  1695.       *to++ = *from;
  1696.  
  1697.   return to - syms;
  1698. }
  1699.  
  1700.  
  1701. /* Update the __.SYMDEF data before writing a new archive.  */
  1702.  
  1703. void
  1704. update_symdefs (map, archive_indesc)
  1705.      struct mapelt *map;
  1706.      int archive_indesc;
  1707. {
  1708.   struct mapelt *tail;
  1709.   int pos;
  1710.   register unsigned int i;
  1711.   unsigned int len;
  1712.   struct symdef *s;
  1713.   unsigned long int deleted_strings_size = 0;
  1714.  
  1715.   nsymdefs = original_num_symdefs;
  1716.   num_old_symdefs = original_num_symdefs;
  1717.   new_strings_size = old_strings_size;
  1718.  
  1719.   if (nsymdefs != 0)
  1720.     {
  1721.       /* We already had a __.SYMDEF member, so just update it.  */
  1722.  
  1723.       /* Mark as canceled any old symdefs for members being deleted.  */
  1724.  
  1725.       for (tail = map; tail != 0; tail = tail->next)
  1726.     {
  1727.       if (tail->info.name == 0)
  1728.         {
  1729.           /* Old member being deleted.  Delete its symdef entries too.  */
  1730.           for (i = 0; i < nsymdefs; i++)
  1731.         if (old_symdefs[i].offset == tail->info.offset)
  1732.           {
  1733.             old_symdefs[i].offset = 0;
  1734.             --nsymdefs;
  1735.             deleted_strings_size
  1736.               += strlen (old_strings
  1737.                  + old_symdefs[i].s.stringoffset) + 1;
  1738.           }
  1739.         }
  1740.     }
  1741.  
  1742.       /* Compactify old symdefs.  */
  1743.       {
  1744.     register unsigned int j = 0;
  1745.     for (i = 0; i < num_old_symdefs; ++i)
  1746.       {
  1747.         if (j != i)
  1748.           old_symdefs[j] = old_symdefs[i];
  1749.         if (old_symdefs[i].offset != 0)
  1750.           ++j;
  1751.       }
  1752.     num_old_symdefs -= i - j;
  1753.       }
  1754.  
  1755.       /* Create symdef data for any new members.  */
  1756.       for (tail = map; tail != 0; tail = tail->next)
  1757.     {
  1758.       if (tail->info.offset != 0
  1759.           || tail->info.name == 0
  1760.           || !strcmp (tail->info.name, "__.SYMDEF"))
  1761.         continue;
  1762.       make_new_symdefs (tail, archive_indesc);
  1763.       nsymdefs += tail->info.nsymdefs;
  1764.       new_strings_size += tail->info.string_size;
  1765.     }
  1766.     }
  1767.   else
  1768.     {
  1769.       /* Create symdef data for all existing members.  */
  1770.  
  1771.       for (tail = map; tail != 0; tail = tail->next)
  1772.     {
  1773.       if (tail->info.name == 0
  1774.           || !strcmp (tail->info.name, "__.SYMDEF"))
  1775.         continue;
  1776.       make_new_symdefs (tail, archive_indesc);
  1777.       nsymdefs += tail->info.nsymdefs;
  1778.       new_strings_size += tail->info.string_size;
  1779.     }
  1780.     }
  1781.  
  1782.   new_strings_size -= deleted_strings_size;
  1783.   old_strings_size -= deleted_strings_size;
  1784.  
  1785.   /* Now we know the size of __.SYMDEF,
  1786.      so assign the positions of all the members.  */
  1787.  
  1788.   tail = find_mapelt_noerror (map, "__.SYMDEF");
  1789.   tail->info.size = (sizeof (nsymdefs) + (nsymdefs * sizeof (struct symdef))
  1790.              + sizeof (new_strings_size) + new_strings_size);
  1791.   symdef_mapelt = tail;
  1792.  
  1793.   pos = SARMAG;
  1794.   for (tail = map; tail != 0; tail = tail->next)
  1795.     {
  1796.       if (tail->info.name == 0)
  1797.     /* Ignore deleted members.  */
  1798.     continue;
  1799.       tail->info.new_offset = pos;
  1800.       pos += sizeof (struct ar_hdr) + tail->info.size;
  1801.       if (tail->info.size & 1)
  1802.     ++pos;
  1803.     }
  1804.  
  1805.   /* Now update the offsets in the symdef data
  1806.      to be the new offsets rather than the old ones.  */
  1807.  
  1808.   for (tail = map; tail != 0; tail = tail->next)
  1809.     {
  1810.       if (tail->info.name == 0)
  1811.     continue;
  1812.       if (tail->info.symdefs == 0)
  1813.     /* Member without new symdef data.
  1814.        Check the old symdef data; it may be included there. */
  1815.     for (i = 0; i < num_old_symdefs; i++)
  1816.       {
  1817.         if (old_symdefs[i].offset == tail->info.offset)
  1818.           old_symdefs[i].offset = tail->info.new_offset;
  1819.       }
  1820.       else
  1821.     for (i = 0; i < tail->info.nsymdefs; i++)
  1822.       tail->info.symdefs[i].offset = tail->info.new_offset;
  1823.     }
  1824.  
  1825.   /* Generate new, combined string table and put each string's offset into the
  1826.      symdef that refers to it.  Note that old symdefs ref their strings by
  1827.      offsets into old_strings but new symdefs contain addresses of strings.  */
  1828.  
  1829.   new_strings = (char *) xmalloc (new_strings_size);
  1830.   pos = 0;
  1831.  
  1832.   /* Write the strings of the old symdefs and update the structures
  1833.      to contain indices into the string table instead of strings.  */
  1834.   for (i = 0; i < num_old_symdefs; i++)
  1835.     {
  1836.       strcpy (new_strings + pos, old_strings + old_symdefs[i].s.stringoffset);
  1837.       old_symdefs[i].s.stringoffset = pos;
  1838.       pos += strlen (new_strings + pos) + 1;
  1839.     }
  1840.   if (pos < old_strings_size)
  1841.     {
  1842.       unsigned int d = old_strings_size - pos;
  1843.       /* Correct the string table size.  */
  1844.       new_strings_size -= d;
  1845.       /* Correct the size of the `__.SYMDEF' member,
  1846.      since it contains the string table.  */
  1847.       symdef_mapelt->info.size -= d;
  1848.     }
  1849.   else if (pos > old_strings_size)
  1850.     fatal ("Old archive's string size was %u too small.",
  1851.        pos - old_strings_size);
  1852.  
  1853.   for (tail = map; tail != 0; tail = tail->next)
  1854.     if (tail->info.symdefs)
  1855.       {
  1856.     len = tail->info.nsymdefs;
  1857.     s = tail->info.symdefs;
  1858.  
  1859.     for (i = 0; i < len; i++)
  1860.       {
  1861.         strcpy (new_strings + pos, s[i].s.name);
  1862.         s[i].s.stringoffset = pos;
  1863.         pos += strlen (new_strings + pos) + 1;
  1864.       }
  1865.       }
  1866.   if (pos != new_strings_size)
  1867.     fatal ("internal error: inconsistency in new_strings_size", 0);
  1868. }
  1869.  
  1870. /* Print error message and usage message, and exit.  */
  1871.  
  1872. void
  1873. usage (s1, s2)
  1874.      char *s1, *s2;
  1875. {
  1876.   error (s1, s2);
  1877.   fprintf (stderr, "\
  1878. Usage: ar [d|m|p|q|r|t|x [[abi [position-name] [cilouv]] archive file...\n");
  1879.   exit (1);
  1880. }
  1881.  
  1882. /* Print error message and exit.  */
  1883.  
  1884. void
  1885. fatal (s1, s2)
  1886.      char *s1, *s2;
  1887. {
  1888.   error (s1, s2);
  1889.   exit (1);
  1890. }
  1891.  
  1892. /* Print error message.  `s1' is printf control string, the rest are args.  */
  1893.  
  1894. void
  1895. error (s1, s2, s3, s4, s5)
  1896.      char *s1, *s2, *s3, *s4, *s5;
  1897. {
  1898.   fprintf (stderr, "ar: ");
  1899.   fprintf (stderr, s1, s2, s3, s4, s5);
  1900.   fprintf (stderr, "\n");
  1901. }
  1902.  
  1903. void
  1904. error_with_file (string, mapelt)
  1905.      char *string;
  1906.      struct mapelt *mapelt;
  1907. {
  1908.   fprintf (stderr, "ar: ");
  1909.   fprintf (stderr, string);
  1910.   if (mapelt->info.offset != 0)
  1911.     fprintf (stderr, "%s(%s)", archive, mapelt->info.name);
  1912.   else
  1913.     fprintf (stderr, "%s", mapelt->info.name);
  1914.   fprintf (stderr, "\n");
  1915. }
  1916.  
  1917. void
  1918. perror_with_name (name)
  1919.      char *name;
  1920. {
  1921.   extern int errno, sys_nerr;
  1922.   extern char *sys_errlist[];
  1923.   char *s;
  1924.  
  1925.   if (errno < sys_nerr)
  1926.     s = concat ("", sys_errlist[errno], " for %s");
  1927.   else
  1928.     s = "unknown error for %s";
  1929.   error (s, name);
  1930. }
  1931.  
  1932. void
  1933. pfatal_with_name (name)
  1934.      char *name;
  1935. {
  1936.   extern int errno, sys_nerr;
  1937.   extern char *sys_errlist[];
  1938.   char *s;
  1939.  
  1940.   if (errno < sys_nerr)
  1941.     s = concat ("", sys_errlist[errno], " for %s");
  1942.   else
  1943.     s = "cannot open %s";
  1944.   fatal (s, name);
  1945. }
  1946.  
  1947. /* Return a newly-allocated string whose contents
  1948.    concatenate those of S1, S2, and S3.  */
  1949.  
  1950. char *
  1951. concat (s1, s2, s3)
  1952.      char *s1, *s2, *s3;
  1953. {
  1954.   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  1955.   char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
  1956.  
  1957.   strcpy (result, s1);
  1958.   strcpy (result + len1, s2);
  1959.   strcpy (result + len1 + len2, s3);
  1960.   *(result + len1 + len2 + len3) = 0;
  1961.  
  1962.   return result;
  1963. }
  1964.  
  1965. /* Like malloc but get fatal error if memory is exhausted.  */
  1966.  
  1967. char *
  1968. xmalloc (size)
  1969.      unsigned int size;
  1970. {
  1971.   extern char *malloc ();
  1972.   char *result = malloc (size);
  1973. #ifdef MCH_AMIGA
  1974.   if (!size && !result) result = "";
  1975. #endif
  1976.   if (result == 0)
  1977.     fatal ("virtual memory exhausted", 0);
  1978.   return result;
  1979. }
  1980.  
  1981. char *
  1982. xrealloc (ptr, size)
  1983.      char *ptr;
  1984.      unsigned int size;
  1985. {
  1986.   extern char *realloc ();
  1987.   char *result = realloc (ptr, size);
  1988. #ifdef MCH_AMIGA
  1989.   if (!size && !result) result = "";
  1990. #endif
  1991.   if (result == 0)
  1992.     fatal ("virtual memory exhausted");
  1993.   return result;
  1994. }
  1995.  
  1996. #ifdef    USG
  1997. #ifndef MCH_AMIGA
  1998. int
  1999. rename (from, to)
  2000.      char *from, *to;
  2001. {
  2002.   (void)unlink (to);
  2003.   if (link (from, to) < 0
  2004.       || unlink (from) < 0)
  2005.     return -1;
  2006.   else
  2007.     return 0;
  2008. }
  2009. #else
  2010.  
  2011. #include <exec/types.h>
  2012. #include <libraries/dos.h>
  2013. #include <inline/dos.h>
  2014.  
  2015. int
  2016. rename (const char *from, const char *to)
  2017. {
  2018.   DeleteFile (to);
  2019.   return Rename (from, to) ? 0 : -1;
  2020. }
  2021.  
  2022. void
  2023. _abort(void)
  2024. {
  2025.   write(2, "^C\n", 3);
  2026.   exit(1);
  2027. }
  2028. #endif
  2029. #endif
  2030.