* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / linux86-0.16.17 / ar / ar.c
blob8443fd9b9f2123ae8f8d36dc4795b2d2da50dc54
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>
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.
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.
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. */
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"
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
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
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
63 /* Locking is normally disabled because fcntl hangs on the Sun
64 and it isn't supported properly across NFS anyway. */
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. */
69 struct member_desc
71 /* Name of member. */
72 char *name;
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. */
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 */
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. */
94 /* Each symbol is recorded by something like this. */
96 struct symdef
98 union
100 unsigned long int stringoffset;
101 char *name;
102 } s;
103 unsigned long int offset;
106 /* Nonzero means it's the name of an existing member;
107 position new or moved files with respect to this one. */
109 char *posname;
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. */
116 enum { POS_DEFAULT, POS_BEFORE, POS_AFTER } postype;
118 /* Nonzero means describe each action performed. */
120 int verbose;
122 /* Nonzero means don't warn about creating the archive file if necessary. */
124 int silent_create;
126 /* Nonzero means don't replace existing members whose
127 dates are more recent than the corresponding files. */
129 int newer_only;
131 /* Nonzero means preserve dates of members when extracting them. */
133 int preserve_dates;
135 /* Operation to be performed. */
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
145 int operation;
147 /* Name of archive file. */
149 char *archive;
151 /* Descriptor on which we have locked the original archive file,
152 or -1 if this has not been done. */
154 int lock_indesc;
156 /* Pointer to tail of `argv', at first subfile name argument,
157 or zero if no such were specified. */
159 char **files;
161 /* Nonzero means write a __.SYMDEF member into the modified archive. */
162 int symdef_flag;
164 /* Nonzero means __.SYMDEF member exists in old archive. */
165 int symdef_exists;
167 /* Nonzero means don't update __.SYMDEF unless the flag was given. */
168 int ignore_symdef;
170 /* Total number of symdef entries we will have. */
171 unsigned long int nsymdefs;
173 /* Symdef data from old archive (set up only if we need it) */
174 struct symdef *old_symdefs;
176 /* Number of symdefs in remaining in old_symdefs. */
177 unsigned int num_old_symdefs;
179 /* Number of symdefs old_symdefs had when it was read in. */
180 unsigned long int original_num_symdefs;
182 /* String table from old __.SYMDEF member. */
183 char *old_strings;
185 /* Size of old_strings */
186 unsigned long int old_strings_size;
188 /* String table to be written into __.SYMDEF member. */
189 char *new_strings;
191 /* Size of new_strings */
192 unsigned long int new_strings_size;
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. */
198 struct mapelt
200 struct member_desc info;
201 struct mapelt *next;
204 struct mapelt *maplast;
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;
210 /* Header that we wrote for the __.SYMDEF member. */
211 struct ar_hdr symdef_header;
213 /* Name this program was run with. */
214 char *program_name;
216 #ifndef __STDC__
217 char *xmalloc (), *xrealloc ();
218 void free ();
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);
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
294 /* Output BYTES of data at BUF to the descriptor DESC.
295 FILE is the name of the file (for error messages). */
297 void
298 mywrite (desc, pbuf, bytes, file)
299 int desc;
300 void *pbuf;
301 int bytes;
302 char *file;
304 register int val;
305 register char * buf = pbuf;
307 while (bytes > 0)
309 val = write (desc, buf, bytes);
310 if (val <= 0)
311 perror_with_name (file);
312 buf += val;
313 bytes -= val;
318 main (argc, argv)
319 int argc;
320 char **argv;
322 int i;
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;
338 program_name = argv[0];
340 if (argc < 2)
341 usage ("too few command arguments", 0);
344 char *key = argv[1];
345 char *p = key;
346 char c;
348 if (*p == '-')
349 p++;
350 while ((c = *p++))
352 switch (c)
354 case 'a':
355 postype = POS_AFTER;
356 break;
358 case 'b':
359 postype = POS_BEFORE;
360 break;
362 case 'c':
363 silent_create = 1;
364 break;
366 case 'd':
367 if (operation)
368 two_operations ();
370 operation = DELETE;
371 break;
373 case 'i':
374 postype = POS_BEFORE;
375 break;
377 case 'l':
378 break;
380 case 'm':
381 if (operation)
382 two_operations ();
383 operation = MOVE;
384 break;
386 case 'o':
387 preserve_dates = 1;
388 break;
390 case 'p':
391 if (operation)
392 two_operations ();
393 operation = PRINT_FILES;
394 break;
396 case 'q':
397 if (operation)
398 two_operations ();
399 operation = QUICK_APPEND;
400 break;
402 case 'r':
403 if (operation)
404 two_operations ();
405 operation = REPLACE;
406 break;
408 case 's':
409 symdef_flag = 1;
410 break;
412 case 't':
413 if (operation)
414 two_operations ();
415 operation = PRINT_TABLE;
416 break;
418 case 'u':
419 operation = REPLACE;
420 newer_only = 1;
421 break;
423 case 'v':
424 verbose = 1;
425 break;
427 case 'x':
428 if (operation)
429 two_operations ();
430 operation = EXTRACT;
431 break;
437 if (operation == 0 && symdef_flag)
438 operation = REPLACE;
440 if (operation == 0)
441 usage ("no operation specified", 0);
443 i = 2;
445 if (postype != POS_DEFAULT)
447 if (i < argc)
448 posname = argv[i++];
449 else
450 usage ("no position operand", 0);
453 if (i >= argc)
454 usage ("no archive specified", 0);
455 archive = argv[i++];
457 if (i < argc)
459 files = &argv[i];
460 while (i < argc)
461 if (!strcmp (argv[i++], "__.SYMDEF"))
463 ignore_symdef = 1;
464 break;
468 switch (operation)
470 case EXTRACT:
471 extract_members (extract_member);
472 break;
474 case PRINT_TABLE:
475 extract_members (print_descr);
476 break;
478 case PRINT_FILES:
479 extract_members (print_contents);
480 break;
482 case DELETE:
483 if (files != 0)
484 delete_members ();
485 break;
487 case MOVE:
488 if (files != 0)
489 move_members ();
490 break;
492 case REPLACE:
493 if (files != 0 || symdef_flag)
494 replace_members ();
495 break;
497 case QUICK_APPEND:
498 if (files != 0)
499 quick_append ();
500 break;
502 default:
503 usage ("invalid operation %d", operation);
506 exit (0);
509 void
510 two_operations ()
512 usage ("two different operation switches specified", 0);
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;
524 FILE *arcstream = fopen (archive, "r");
526 if (arcstream == 0 && crflag)
527 /* Creation-warning, if desired, will happen later. */
528 return;
530 if (arcstream == 0)
532 perror_with_name (archive);
533 exit (1);
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);
542 /* Now find the members one by one. */
544 int member_offset = SARMAG;
545 while (1)
547 int nread;
548 struct ar_hdr member_header;
549 struct member_desc member_desc;
550 char name [1 + sizeof member_header.ar_name];
552 if (fseek (arcstream, member_offset, 0) < 0)
553 perror_with_name (archive);
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;
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);
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
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);
583 member_desc.new_offset = 0;
584 member_desc.symdefs = 0;
585 member_desc.nsymdefs = 0;
586 member_desc.string_size = 0;
588 if (!ignore_symdef && !strcmp (name, "__.SYMDEF"))
589 symdef_exists = 1;
591 function (member_desc, arcstream);
593 member_offset += sizeof (member_header) + member_desc.size;
594 if (member_offset & 1)
595 ++member_offset;
600 fclose (arcstream);
603 void
604 print_descr (member, instream)
605 struct member_desc member;
606 FILE * instream;
608 char *timestring;
609 if (!verbose)
611 puts (member.name);
612 return;
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);
622 void
623 print_modes (modes)
624 int modes;
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' : '-');
637 #define BUFSIZE 1024
639 void
640 extract_member (member, istream)
641 struct member_desc member;
642 FILE *istream;
644 int ncopied = 0;
645 FILE *ostream;
647 fseek (istream, member.data_offset, 0);
648 ostream = fopen (member.name, "w");
649 if (!ostream)
651 perror_with_name (member.name);
652 return;
655 if (verbose)
656 printf ("x - %s\n", member.name);
658 while (ncopied < member.size)
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;
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);
679 if (preserve_dates)
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
697 void
698 print_contents (member, istream)
699 struct member_desc member;
700 FILE *istream;
702 int ncopied = 0;
704 fseek (istream, member.data_offset, 0);
706 if (verbose)
707 printf ("\n<member %s>\n\n", member.name);
709 while (ncopied < member.size)
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;
723 /* Make a map of the existing members of the archive: their names,
724 positions and sizes. */
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. */
731 struct mapelt *
732 make_map (nonexistent_ok)
733 int nonexistent_ok;
735 struct mapelt mapstart;
736 mapstart.next = 0;
737 maplast = &mapstart;
738 scan (add_to_map, nonexistent_ok);
739 return mapstart.next;
742 void
743 add_to_map (member, istream)
744 struct member_desc member;
745 FILE * istream;
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;
755 /* Return the last element of the specified map. */
757 struct mapelt *
758 last_mapelt (map)
759 struct mapelt *map;
761 struct mapelt *tail = map;
762 while (tail->next) tail = tail->next;
763 return tail;
766 /* Return the element of the specified map which precedes elt. */
768 struct mapelt *
769 prev_mapelt (map, elt)
770 struct mapelt *map, *elt;
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;
779 /* Return the element of the specified map which has the specified name. */
781 struct mapelt *
782 find_mapelt_noerror (map, name)
783 struct mapelt *map;
784 register char *name;
786 register struct mapelt *tail;
787 unsigned int len;
788 int dot_o;
790 name = basename (name);
791 len = strlen (name);
792 dot_o = name[len - 2] == '.' && name[len - 1] == 'o';
794 for (tail = map; tail != 0; tail = tail->next)
796 if (tail->info.name == 0)
797 continue;
798 if (!strncmp (tail->info.name, name, 13))
800 unsigned int eltlen = strlen (tail->info.name);
801 if (len <= 13 || eltlen <= 13)
802 return tail;
803 else
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;
815 return 0;
818 struct mapelt *
819 find_mapelt (map, name)
820 struct mapelt *map;
821 char *name;
823 register struct mapelt *found = find_mapelt_noerror (map, name);
824 if (found == 0)
825 error ("no member named `%s'", name);
826 return found;
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. */
833 void
834 lock_for_update ()
836 /* Open the existing archive file; if that fails, create an empty one. */
838 lock_indesc = open (archive, O_RDWR, 0);
840 if (lock_indesc < 0)
842 int outdesc;
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);
852 /* Now we had better be able to open for update! */
854 lock_indesc = open (archive, O_RDWR, 0);
855 if (lock_indesc < 0)
857 unlink (archive);
858 pfatal_with_name (archive);
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.)
867 Note that merely reading an archive does not require a lock,
868 because we use `rename' to update the whole file atomically. */
871 struct flock lock;
873 lock.l_type = F_WRLCK;
874 lock.l_whence = 0;
875 lock.l_start = 0;
876 lock.l_len = 0;
878 while (1)
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");
889 #endif
892 /* Unlock archive and close the file descriptor. */
894 void
895 close_archive ()
897 #ifdef LOCKS
899 struct flock lock;
901 /* Unlock the old archive. */
903 lock.l_type = F_UNLCK;
904 lock.l_whence = 0;
905 lock.l_start = 0;
906 lock.l_len = 0;
908 fcntl (lock_indesc, F_SETLK, &lock);
910 #endif
912 /* Close the archive. If we renamed a new one, the old one disappears. */
913 close (lock_indesc);
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.
921 Ordinarily, the element describes a member of the old
922 archive, to be copied into the new one.
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.
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.
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.
936 void
937 write_archive (map, appendflag)
938 struct mapelt *map;
939 int appendflag;
941 char *tempname = make_tempname (archive);
942 int indesc = lock_indesc;
943 int outdesc;
944 char *outname;
945 struct mapelt *tail;
947 /* Now open the output. */
949 if (!appendflag)
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. */
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);
962 else
964 /* Fast-append to existing archive. */
966 outdesc = open (archive, O_WRONLY | O_APPEND, 0);
967 if (outdesc < 0)
968 pfatal_with_name (archive);
969 outname = archive;
972 /* If archive has or should have a __.SYMDEF member,
973 compute the contents for it. */
975 if (symdef_flag || symdef_exists)
977 if (symdef_exists)
978 read_old_symdefs (map, indesc);
979 else
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;
1001 update_symdefs (map, indesc);
1004 /* Copy the members into the output, either from the old archive
1005 or from specified files. */
1007 for (tail = map; tail != 0; tail = tail->next)
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
1015 write_symdef_member (tail, map, outdesc, outname);
1016 else
1017 copy_out_member (tail, indesc, outdesc, outname);
1020 if (symdef_mapelt != 0)
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)
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;
1034 if (doneany)
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);
1042 /* Mark the __.SYMDEF member as up to date. */
1044 if (symdef_mapelt != 0)
1045 touch_symdef_member (outdesc, outname);
1047 /* Install the new output under the intended name. */
1049 #ifdef HAVE_FSYNC
1050 fsync (outdesc);
1051 #endif
1052 close (outdesc);
1054 if (!appendflag)
1055 if (rename (tempname, archive))
1056 pfatal_with_name (tempname);
1058 close_archive ();
1061 void
1062 header_from_map (header, mapelt)
1063 struct ar_hdr *header;
1064 struct mapelt *mapelt;
1066 unsigned int namelen;
1067 char *p;
1069 /* Zero the header, then store in the data as text. */
1070 bzero ((char *) header, sizeof (*header));
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))
1077 if (mapelt->info.name[namelen - 2] == '.' &&
1078 mapelt->info.name[namelen - 1] == 'o')
1080 header->ar_name[sizeof (header->ar_name) - 3] = '.';
1081 header->ar_name[sizeof (header->ar_name) - 2] = 'o';
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);
1087 #if defined(USG) || defined(HAVE_TRAILING_SLASH_IN_NAME)
1089 /* System V tacks a trailing '/' onto the end of the name */
1090 char *p = header->ar_name;
1091 char *end = p + sizeof (header->ar_name);
1093 while (p < end && *p)
1094 p++;
1095 *p = '/';
1097 #endif
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));
1106 /* Change all remaining nulls in the header into spaces. */
1108 char *end = (char *) &header[1];
1109 register char *p;
1110 for (p = (char *) header; p < end; ++p)
1111 if (*p == '\0')
1112 *p = ' ';
1116 /* gets just the file part of name */
1118 char *
1119 basename (path)
1120 char *path;
1122 char *save, *start;
1123 for (start = save = path; *path; path++)
1124 if (*path == '/')
1125 save = path + 1;
1127 if (save != start)
1128 return save;
1129 else
1130 return start;
1133 /* writes to file open on OUTDESC with name OUTNAME. */
1134 void
1135 copy_out_member (mapelt, archive_indesc, outdesc, outname)
1136 struct mapelt *mapelt;
1137 int archive_indesc;
1138 int outdesc;
1139 char *outname;
1141 struct ar_hdr header;
1142 int indesc;
1144 if (mapelt->info.name == 0)
1145 /* This element was cancelled. */
1146 return;
1148 header_from_map (&header, mapelt);
1150 if (mapelt->info.offset != 0)
1152 indesc = archive_indesc;
1153 lseek (indesc, mapelt->info.data_offset, 0);
1155 else
1157 indesc = open (mapelt->info.name, 0, 0);
1158 if (indesc < 0)
1160 perror_with_name (mapelt->info.name);
1161 return;
1165 mywrite (outdesc, &header, sizeof (header), outname);
1167 if (mapelt->info.data_offset == 0)
1168 mapelt->info.data_offset = lseek (outdesc, 0L, 1);
1171 char buf[BUFSIZE];
1172 int tocopy = mapelt->info.size;
1173 while (tocopy > 0)
1175 int thistime = tocopy;
1176 if (thistime > BUFSIZE) thistime = BUFSIZE;
1177 read (indesc, buf, thistime);
1178 mywrite (outdesc, buf, thistime, outname);
1179 tocopy -= thistime;
1183 if (indesc != archive_indesc)
1184 close (indesc);
1186 if (mapelt->info.size & 1)
1187 mywrite (outdesc, "\n", 1, outname);
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. */
1194 void
1195 touch_symdef_member (outdesc, outname)
1196 int outdesc;
1197 char *outname;
1199 struct stat statbuf;
1200 int i;
1202 /* See what mtime the archive file has as a result of our writing it. */
1203 fstat (outdesc, &statbuf);
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] = ' ';
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);
1217 char *
1218 make_tempname (name)
1219 char *name;
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;
1226 if (p != name)
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);
1233 else if (strlen (name) >= 14)
1234 return concat ("t_", name, "");
1235 else
1236 #endif
1237 return concat (name, "", "_supersede");
1240 void
1241 delete_members ()
1243 struct mapelt *map = make_map (0);
1244 struct mapelt mapstart;
1245 char **p;
1247 mapstart.info.name = 0;
1248 mapstart.next = map;
1249 map = &mapstart;
1251 lock_for_update ();
1253 if (files)
1254 for (p = files; *p; p++)
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);
1263 write_archive (map->next, 0);
1266 void
1267 delete_from_map (name, map)
1268 char *name;
1269 struct mapelt *map;
1271 struct mapelt *this = find_mapelt (map, name);
1273 if (!this) return;
1274 this->info.name = 0;
1275 if (verbose)
1276 printf ("d - %s\n", name);
1279 void
1280 move_members ()
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;
1288 mapstart.info.name = 0;
1289 mapstart.next = map;
1290 change_map = &mapstart;
1292 lock_for_update ();
1294 switch (postype)
1296 case POS_DEFAULT:
1297 after_mapelt = last_mapelt (change_map);
1298 break;
1300 case POS_AFTER:
1301 after_mapelt = find_mapelt (map, posname);
1302 break;
1304 case POS_BEFORE:
1305 after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
1308 /* Failure to find specified "before" or "after" member
1309 is a fatal error; message has already been printed. */
1311 if (!after_mapelt) exit (1);
1313 if (files)
1314 for (p = files; *p; p++)
1316 if (move_in_map (*p, change_map, after_mapelt))
1317 after_mapelt = after_mapelt->next;
1320 write_archive (map, 0);
1324 move_in_map (name, map, after)
1325 char *name;
1326 struct mapelt *map, *after;
1328 struct mapelt *this = find_mapelt (map, name);
1329 struct mapelt *prev;
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;
1339 /* Insert files into the archive. */
1341 void
1342 replace_members ()
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;
1351 mapstart.info.name = 0;
1352 mapstart.next = map;
1353 change_map = &mapstart;
1355 lock_for_update ();
1357 switch (postype)
1359 case POS_DEFAULT:
1360 after_mapelt = last_mapelt (change_map);
1361 break;
1363 case POS_AFTER:
1364 after_mapelt = find_mapelt (map, posname);
1365 break;
1367 case POS_BEFORE:
1368 after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
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);
1376 changed = 0;
1377 if (files != 0)
1378 for (p = files; *p != 0; ++p)
1379 if (insert_in_map (*p, change_map, after_mapelt))
1381 after_mapelt = after_mapelt->next;
1382 changed = 1;
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);
1393 /* Handle the "quick insert" operation. */
1395 void
1396 quick_append ()
1398 struct mapelt *map;
1399 struct mapelt *after;
1400 struct mapelt mapstart;
1401 char **p;
1403 mapstart.info.name = 0;
1404 mapstart.next = 0;
1405 map = &mapstart;
1406 after = map;
1408 lock_for_update ();
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++)
1416 if (insert_in_map (*p, map, after))
1417 after = after->next;
1420 /* Append these files to the end of the existing archive file. */
1422 write_archive (map->next, 1);
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. */
1433 insert_in_map (name, map, after)
1434 char *name;
1435 struct mapelt *map, *after;
1437 struct mapelt *old = find_mapelt_noerror (map, name);
1438 struct mapelt *this;
1439 struct stat status;
1441 if (stat (name, &status))
1443 perror_with_name (name);
1444 return 0;
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;
1467 if (verbose)
1468 printf ("%c - %s\n", old == 0 ? 'a' : 'r', this->info.name);
1470 return 1;
1473 /* Apply a function to each of the specified members.
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
1484 struct mapelt *map;
1485 FILE *arcstream;
1486 char **p;
1488 if (!files)
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;
1496 arcstream = fopen (archive, "r");
1497 if (!arcstream)
1498 fatal ("failure opening archive %s for the second time", archive);
1499 map = make_map (0);
1501 for (p = files; *p; p++)
1503 struct mapelt *this = find_mapelt (map, *p);
1504 if (!this) continue;
1505 function (this->info, arcstream);
1508 fclose (arcstream);
1512 /* Write the __.SYMDEF member from data in core. OUTDESC and OUTNAME
1513 are descriptor and name of file to write to. */
1515 void
1516 write_symdef_member (mapelt, map, outdesc, outname)
1517 struct mapelt *mapelt;
1518 struct mapelt *map;
1519 int outdesc;
1520 char *outname;
1522 struct ar_hdr header;
1523 struct mapelt *mapptr;
1524 unsigned long int symdefs_size;
1526 if (mapelt->info.name == 0)
1527 /* This element was cancelled. */
1528 return;
1530 header_from_map (&header, mapelt);
1532 bcopy (&header, &symdef_header, sizeof header);
1534 mywrite (outdesc, &header, sizeof (header), outname);
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);
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
1556 /* Write symdefs for new members. */
1557 for (mapptr = map; mapptr != 0; mapptr = mapptr->next)
1558 if (mapptr->info.nsymdefs != 0)
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
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
1585 /* Write the string table. */
1586 mywrite (outdesc, new_strings, new_strings_size, outname);
1588 if (mapelt->info.size & 1)
1589 mywrite (outdesc, "", 1, outname);
1592 void
1593 read_old_symdefs (map, archive_indesc)
1594 struct mapelt *map;
1595 int archive_indesc;
1597 struct mapelt *mapelt;
1598 char *data;
1599 int val;
1600 int symdefs_size;
1602 mapelt = find_mapelt_noerror (map, "__.SYMDEF");
1603 if (!mapelt)
1604 abort (); /* Only call here if an old one exists */
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);
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
1635 /* Read various information from the header of an object file.
1636 Return 0 for failure or 1 for success. */
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;
1648 struct exec hdr;
1649 int len;
1651 lseek (desc, offset, 0);
1652 #ifdef HEADER_SEEK_FD
1653 HEADER_SEEK_FD (desc);
1654 #endif
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))
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)
1668 error_with_file ("failure reading string table size in ", mapelt);
1669 return 0;
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;
1678 error_with_file ("bad format (not an object file) in ", mapelt);
1679 return 0;
1682 /* Create the info.symdefs for a new member
1683 by reading the file it is coming from. */
1685 void
1686 make_new_symdefs (mapelt, archive_indesc)
1687 struct mapelt *mapelt;
1688 int archive_indesc;
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;
1700 if (name == 0)
1701 /* Deleted member. */
1702 abort ();
1704 if (mapelt->info.offset != 0)
1706 indesc = archive_indesc;
1707 lseek (indesc, mapelt->info.data_offset, 0);
1708 offset = mapelt->info.data_offset;
1710 else
1712 indesc = open (mapelt->info.name, 0, 0);
1713 if (indesc < 0)
1715 perror_with_name (mapelt->info.name);
1716 return;
1718 offset = 0;
1721 if (!read_header_info (mapelt, indesc, offset, &syms_offset, &syms_size, &strs_offset, &strs_size))
1723 if (mapelt->info.offset == 0)
1724 close (indesc);
1725 return;
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)
1736 error_with_file ("premature end of file in symbols of ", mapelt);
1737 if (mapelt->info.offset == 0)
1738 (void) close (indesc);
1739 return;
1741 #ifdef HOST_TARGET_ENDIANESS_DIFFERS
1742 md_chars_to_nlist ((unsigned char *) symbols, symbols, symcount);
1743 #endif
1745 /* The string table size includes the size word. */
1746 if (strs_size < sizeof (strs_size))
1748 error_with_file ("bad string table size in ", mapelt);
1749 if (mapelt->info.offset == 0)
1750 (void) close (indesc);
1751 return;
1753 strs_size -= sizeof (strs_size);
1755 /* Allocate permanent space for the string table. */
1756 strings = (char *) xmalloc (strs_size);
1758 /* Read in the strings. */
1759 lseek (indesc, offset + strs_offset + sizeof strs_size, 0);
1760 if (read (indesc, strings, strs_size) != strs_size)
1762 error_with_file ("premature end of file in strings of ", mapelt);
1763 if (mapelt->info.offset == 0)
1764 (void) close (indesc);
1765 return;
1768 if (indesc != archive_indesc)
1769 (void) close (indesc);
1771 /* Discard the symbols we don't want to mention; compact the rest down. */
1772 symcount = filter_symbols (symbols, symcount);
1774 mapelt->info.symdefs = (struct symdef *)
1775 xmalloc (symcount * sizeof (struct symdef));
1776 mapelt->info.nsymdefs = symcount;
1777 mapelt->info.string_size = 0;
1779 for (i = 0; i < symcount; ++i)
1781 unsigned long int stroff = symbols[i].n_un.n_strx - sizeof (strs_size);
1782 char *symname = strings + stroff;
1783 if (stroff > strs_size)
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;
1791 mapelt->info.symdefs[i].s.name = symname;
1792 mapelt->info.string_size += strlen (symname) + 1;
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. */
1801 filter_symbols (syms, symcount)
1802 struct nlist *syms;
1803 unsigned int symcount;
1805 struct nlist *from, *to;
1806 struct nlist *end = syms + symcount;
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;
1813 return to - syms;
1817 /* Update the __.SYMDEF data before writing a new archive. */
1819 void
1820 update_symdefs (map, archive_indesc)
1821 struct mapelt *map;
1822 int archive_indesc;
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;
1831 nsymdefs = original_num_symdefs;
1832 num_old_symdefs = original_num_symdefs;
1833 new_strings_size = old_strings_size;
1835 if (nsymdefs != 0)
1837 /* We already had a __.SYMDEF member, so just update it. */
1839 /* Mark as canceled any old symdefs for members being deleted. */
1841 for (tail = map; tail != 0; tail = tail->next)
1843 if (tail->info.name == 0)
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)
1849 old_symdefs[i].offset = 0;
1850 --nsymdefs;
1851 deleted_strings_size
1852 += strlen (old_strings
1853 + old_symdefs[i].s.stringoffset) + 1;
1858 /* Compactify old symdefs. */
1860 register unsigned int j = 0;
1861 for (i = 0; i < num_old_symdefs; ++i)
1863 if (j != i)
1864 old_symdefs[j] = old_symdefs[i];
1865 if (old_symdefs[i].offset != 0)
1866 ++j;
1868 num_old_symdefs -= i - j;
1871 /* Create symdef data for any new members. */
1872 for (tail = map; tail != 0; tail = tail->next)
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;
1883 else
1885 /* Create symdef data for all existing members. */
1887 for (tail = map; tail != 0; tail = tail->next)
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;
1898 new_strings_size -= deleted_strings_size;
1899 old_strings_size -= deleted_strings_size;
1901 /* Now we know the size of __.SYMDEF,
1902 so assign the positions of all the members. */
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;
1909 pos = SARMAG;
1910 for (tail = map; tail != 0; tail = tail->next)
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;
1921 /* Now update the offsets in the symdef data
1922 to be the new offsets rather than the old ones. */
1924 for (tail = map; tail != 0; tail = tail->next)
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++)
1933 if (old_symdefs[i].offset == tail->info.offset)
1934 old_symdefs[i].offset = tail->info.new_offset;
1936 else
1937 for (i = 0; i < tail->info.nsymdefs; i++)
1938 tail->info.symdefs[i].offset = tail->info.new_offset;
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. */
1945 new_strings = (char *) xmalloc (new_strings_size);
1946 pos = 0;
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++)
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;
1956 if (pos < old_strings_size)
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;
1965 else if (pos > old_strings_size)
1966 fatal ("Old archive's string size was %u too small.",
1967 (void*)(pos - old_strings_size));
1969 for (tail = map; tail != 0; tail = tail->next)
1970 if (tail->info.symdefs)
1972 len = tail->info.nsymdefs;
1973 s = tail->info.symdefs;
1975 for (i = 0; i < len; i++)
1977 strcpy (new_strings + pos, s[i].s.name);
1978 s[i].s.stringoffset = pos;
1979 pos += strlen (new_strings + pos) + 1;
1982 if (pos != new_strings_size)
1983 fatal ("internal error: inconsistency in new_strings_size", 0);
1987 /* Print error message and usage message, and exit. */
1989 void
1990 usage (s1, val)
1991 char *s1;
1992 int val;
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);
2003 /* Print error message and exit. */
2005 void
2006 fatal (s1, s2)
2007 char *s1, *s2;
2009 error (s1, s2);
2010 exit (1);
2013 /* Print error message. `s1' is printf control string, the rest are args. */
2015 void
2016 error (s1, s2)
2017 char *s1, *s2;
2019 fprintf (stderr, "%s: ", program_name);
2020 fprintf (stderr, s1, s2);
2021 fprintf (stderr, "\n");
2024 void
2025 error3 (s1, s2, s3)
2026 char *s1, *s2, *s3;
2028 fprintf (stderr, "%s: ", program_name);
2029 fprintf (stderr, s1, s2, s3);
2030 fprintf (stderr, "\n");
2033 void
2034 error_with_file (string, mapelt)
2035 char *string;
2036 struct mapelt *mapelt;
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");
2047 void
2048 perror_with_name (name)
2049 char *name;
2051 error (concat ("", strerror(errno), " for %s"), name);
2054 void
2055 pfatal_with_name (name)
2056 char *name;
2058 fatal (concat ("", strerror(errno), " for %s"), name);
2061 /* Return a newly-allocated string whose contents
2062 concatenate those of S1, S2, and S3. */
2064 char *
2065 concat (s1, s2, s3)
2066 const char *s1, *s2, *s3;
2068 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
2069 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
2071 strcpy (result, s1);
2072 strcpy (result + len1, s2);
2073 strcpy (result + len1 + len2, s3);
2074 *(result + len1 + len2 + len3) = 0;
2076 return result;
2079 /* Like malloc but get fatal error if memory is exhausted. */
2081 char *
2082 xmalloc (size)
2083 unsigned int size;
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;
2095 char *
2096 xrealloc (ptr, size)
2097 char *ptr;
2098 unsigned int size;
2100 char *result = realloc (ptr, size);
2101 if (result == 0)
2102 fatal ("virtual memory exhausted", 0);
2103 return result;
2107 #ifndef HAVE_RENAME
2109 rename (from, to)
2110 char *from, *to;
2112 (void)unlink (to);
2113 if (link (from, to) < 0
2114 || unlink (from) < 0)
2115 return -1;
2116 else
2117 return 0;
2119 #else
2120 #ifdef ATT
2121 int Error;
2122 #endif
2123 #endif