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