xref: /illumos-gate/usr/src/cmd/sgs/ar/common/file.c (revision 683007910b81ed9ff942db7c464d1b6df524048a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  *	Use is subject to license terms.
25  */
26 
27 /*
28  *	Copyright (c) 1988 AT&T
29  *	  All Rights Reserved
30  *
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include "gelf.h"
36 #include "inc.h"
37 #include "extern.h"
38 
39 static char *str_base;	/* start of string table for names */
40 static char *str_top;	/* pointer to next available location */
41 static char *str_base1, *str_top1;
42 static int pad_symtab;
43 
44 
45 /*
46  * Function Prototypes
47  */
48 static long mklong_tab(int *);
49 static char *trimslash(char *s);
50 
51 static long mksymtab(ARFILEP **, Cmd_info *, int *);
52 static int writesymtab(char *, long, ARFILEP *);
53 static void savename(char *);
54 static void savelongname(ARFILE *, char *);
55 static void sputl(long, char *);
56 
57 static char *writelargefile(Cmd_info *cmd_info, long long_tab_size,
58     int longnames, ARFILEP *symlist, long nsyms, int found_obj,
59     int new_archive);
60 
61 static int sizeofmembers();
62 static int sizeofnewarchive(int, int);
63 
64 static int search_sym_tab(ARFILE *, Elf *, Elf_Scn *,
65 	long *, ARFILEP **, int *);
66 
67 #ifdef BROWSER
68 static void sbrowser_search_stab(Elf *, int, int, char *);
69 #endif
70 
71 
72 int
73 getaf(Cmd_info *cmd_info)
74 {
75 	Elf_Cmd cmd;
76 	int fd;
77 	char *arnam = cmd_info->arnam;
78 
79 	if (elf_version(EV_CURRENT) == EV_NONE) {
80 		error_message(ELF_VERSION_ERROR,
81 		LIBELF_ERROR, elf_errmsg(-1));
82 		exit(1);
83 	}
84 
85 	if ((cmd_info->afd = fd = open(arnam, O_RDONLY)) == -1) {
86 		if (errno == ENOENT) {
87 			/* archive does not exist yet, may have to create one */
88 			return (fd);
89 		} else {
90 			/* problem other than "does not exist" */
91 			error_message(SYS_OPEN_ERROR,
92 			SYSTEM_ERROR, strerror(errno), arnam);
93 			exit(1);
94 		}
95 	}
96 
97 	cmd = ELF_C_READ;
98 	cmd_info->arf = elf_begin(fd, cmd, (Elf *)0);
99 
100 	if (elf_kind(cmd_info->arf) != ELF_K_AR) {
101 		error_message(NOT_ARCHIVE_ERROR,
102 		PLAIN_ERROR, (char *)0, arnam);
103 		if (opt_FLAG(cmd_info, a_FLAG) || opt_FLAG(cmd_info, b_FLAG))
104 		    error_message(USAGE_06_ERROR,
105 		    PLAIN_ERROR, (char *)0, cmd_info->ponam);
106 		exit(1);
107 	}
108 	return (fd);
109 }
110 
111 ARFILE *
112 getfile(Cmd_info *cmd_info)
113 {
114 	Elf_Arhdr *mem_header;
115 	ARFILE	*file;
116 	char *tmp_rawname, *file_rawname;
117 	Elf *elf;
118 	char *arnam = cmd_info->arnam;
119 	int fd = cmd_info->afd;
120 	Elf *arf = cmd_info->arf;
121 
122 	if (fd == -1)
123 		return (NULL); /* the archive doesn't exist */
124 
125 	if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
126 		return (NULL);  /* the archive is empty or have hit the end */
127 
128 	if ((mem_header = elf_getarhdr(elf)) == NULL) {
129 		error_message(ELF_MALARCHIVE_ERROR,
130 		LIBELF_ERROR, elf_errmsg(-1),
131 		arnam, elf_getbase(elf));
132 		exit(1);
133 	}
134 
135 	/* zip past special members like the symbol and string table members */
136 
137 	while (strncmp(mem_header->ar_name, "/", 1) == 0 ||
138 		strncmp(mem_header->ar_name, "//", 2) == 0) {
139 		(void) elf_next(elf);
140 		(void) elf_end(elf);
141 		if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
142 			return (NULL);
143 			/* the archive is empty or have hit the end */
144 		if ((mem_header = elf_getarhdr(elf)) == NULL) {
145 			error_message(ELF_MALARCHIVE_ERROR,
146 			LIBELF_ERROR, elf_errmsg(-1),
147 			arnam, elf_getbase(elf));
148 			exit(0);
149 		}
150 	}
151 
152 	/*
153 	 * NOTE:
154 	 *	The mem_header->ar_name[] is set to a NULL string
155 	 *	if the archive member header has some error.
156 	 *	(See elf_getarhdr() man page.)
157 	 *	It is set to NULL for example, the ar command reads
158 	 *	the archive files created by SunOS 4.1 system.
159 	 *	See c block comment in cmd.c, "Incompatible Archive Header".
160 	 */
161 	file = newfile();
162 	(void) strncpy(file->ar_name, mem_header->ar_name, SNAME);
163 
164 	if ((file->ar_longname
165 	    = malloc(strlen(mem_header->ar_name) + 1))
166 	    == NULL) {
167 		error_message(MALLOC_ERROR,
168 		PLAIN_ERROR, (char *)0);
169 		exit(1);
170 	}
171 	(void) strcpy(file->ar_longname, mem_header->ar_name);
172 	if ((file->ar_rawname
173 	    = malloc(strlen(mem_header->ar_rawname) + 1))
174 	    == NULL) {
175 		error_message(MALLOC_ERROR,
176 		PLAIN_ERROR, (char *)0);
177 		exit(1);
178 	}
179 	tmp_rawname = mem_header->ar_rawname;
180 	file_rawname = file->ar_rawname;
181 	while (!isspace(*tmp_rawname) &&
182 		((*file_rawname = *tmp_rawname) != '\0')) {
183 		file_rawname++;
184 		tmp_rawname++;
185 	}
186 	if (!(*tmp_rawname == '\0'))
187 		*file_rawname = '\0';
188 
189 	file->ar_date = mem_header->ar_date;
190 	file->ar_uid  = mem_header->ar_uid;
191 	file->ar_gid  = mem_header->ar_gid;
192 	file->ar_mode = (unsigned long) mem_header->ar_mode;
193 	file->ar_size = mem_header->ar_size;
194 
195 	/* reverse logic */
196 	if (!(opt_FLAG(cmd_info, t_FLAG) && !opt_FLAG(cmd_info, s_FLAG))) {
197 		size_t ptr;
198 		file->ar_flag = F_ELFRAW;
199 		if ((file->ar_contents = elf_rawfile(elf, &ptr))
200 		    == NULL) {
201 			if (ptr != 0) {
202 				error_message(ELF_RAWFILE_ERROR,
203 				LIBELF_ERROR, elf_errmsg(-1));
204 				exit(1);
205 			}
206 		}
207 		file->ar_elf = elf;
208 	}
209 	(void) elf_next(elf);
210 	return (file);
211 }
212 
213 ARFILE *
214 newfile(void)
215 {
216 	static ARFILE	*buffer =  NULL;
217 	static int	count = 0;
218 	ARFILE	*fileptr;
219 
220 	if (count == 0) {
221 		if ((buffer = (ARFILE *) calloc(CHUNK, sizeof (ARFILE)))
222 		    == NULL) {
223 			error_message(MALLOC_ERROR,
224 			PLAIN_ERROR, (char *)0);
225 			exit(1);
226 		}
227 		count = CHUNK;
228 	}
229 	count--;
230 	fileptr = buffer++;
231 
232 	if (listhead)
233 		listend->ar_next = fileptr;
234 	else
235 		listhead = fileptr;
236 	listend = fileptr;
237 	return (fileptr);
238 }
239 
240 static char *
241 trimslash(char *s)
242 {
243 	static char buf[SNAME];
244 
245 	(void) strncpy(buf, trim(s), SNAME - 2);
246 	buf[SNAME - 2] = '\0';
247 	return (strcat(buf, "/"));
248 }
249 
250 char *
251 trim(char *s)
252 {
253 	char *p1, *p2;
254 
255 	for (p1 = s; *p1; p1++)
256 		;
257 	while (p1 > s) {
258 		if (*--p1 != '/')
259 			break;
260 		*p1 = 0;
261 	}
262 	p2 = s;
263 	for (p1 = s; *p1; p1++)
264 		if (*p1 == '/')
265 			p2 = p1 + 1;
266 	return (p2);
267 }
268 
269 
270 static long
271 mksymtab(ARFILEP **symlist, Cmd_info *cmd_info, int *found_obj)
272 {
273 	ARFILE	*fptr;
274 	long	mem_offset = 0;
275 	Elf *elf;
276 	Elf_Scn	*scn;
277 	GElf_Ehdr ehdr;
278 	int newfd;
279 	long nsyms = 0;
280 	int class = 0;
281 	Elf_Data *data;
282 	char *sbshstr;
283 	char *sbshstrtp;
284 	int sbstabsect = -1;
285 	int sbstabstrsect = -1;
286 	int num_errs = 0;
287 
288 	newfd = 0;
289 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
290 		/* determine if file is coming from the archive or not */
291 		if ((fptr->ar_elf != 0) && (fptr->ar_pathname == NULL)) {
292 			/*
293 			 * I can use the saved elf descriptor.
294 			 */
295 			elf = fptr->ar_elf;
296 		} else if ((fptr->ar_elf == 0) &&
297 		    (fptr->ar_pathname != NULL)) {
298 			if ((newfd  =
299 			    open(fptr->ar_pathname, O_RDONLY)) == -1) {
300 				error_message(SYS_OPEN_ERROR,
301 				SYSTEM_ERROR, strerror(errno),
302 				fptr->ar_pathname);
303 				num_errs++;
304 				continue;
305 			}
306 
307 			if ((elf = elf_begin(newfd,
308 					ELF_C_READ,
309 					(Elf *)0)) == 0) {
310 				if (fptr->ar_pathname != NULL)
311 					error_message(ELF_BEGIN_02_ERROR,
312 					LIBELF_ERROR, elf_errmsg(-1),
313 					fptr->ar_pathname);
314 				else
315 					error_message(ELF_BEGIN_03_ERROR,
316 					LIBELF_ERROR, elf_errmsg(-1));
317 				(void) close(newfd);
318 				newfd = 0;
319 				num_errs++;
320 				continue;
321 			}
322 			if (elf_kind(elf) == ELF_K_AR) {
323 				if (fptr->ar_pathname != NULL)
324 					error_message(ARCHIVE_IN_ARCHIVE_ERROR,
325 					PLAIN_ERROR, (char *)0,
326 					fptr->ar_pathname);
327 				else
328 					error_message(ARCHIVE_USAGE_ERROR,
329 					PLAIN_ERROR, (char *)0);
330 				if (newfd) {
331 					(void) close(newfd);
332 					newfd = 0;
333 				}
334 				(void) elf_end(elf);
335 				continue;
336 			}
337 		} else {
338 			error_message(INTERNAL_01_ERROR,
339 			PLAIN_ERROR, (char *)0);
340 			exit(1);
341 		}
342 		if (gelf_getehdr(elf, &ehdr) != 0) {
343 			if ((class = gelf_getclass(elf)) == ELFCLASS64) {
344 				fptr->ar_flag |= F_CLASS64;
345 			} else if (class == ELFCLASS32)
346 				fptr->ar_flag |= F_CLASS32;
347 			scn = elf_getscn(elf, ehdr.e_shstrndx);
348 			if (scn == NULL) {
349 				if (fptr->ar_pathname != NULL)
350 					error_message(ELF_GETSCN_01_ERROR,
351 					LIBELF_ERROR, elf_errmsg(-1),
352 					fptr->ar_pathname);
353 				else
354 					error_message(ELF_GETSCN_02_ERROR,
355 					LIBELF_ERROR, elf_errmsg(-1));
356 				num_errs++;
357 				if (newfd) {
358 					(void) close(newfd);
359 					newfd = 0;
360 				}
361 				(void) elf_end(elf);
362 				continue;
363 			}
364 
365 			data = 0;
366 			data = elf_getdata(scn, data);
367 			if (data == NULL) {
368 				if (fptr->ar_pathname != NULL)
369 					error_message(ELF_GETDATA_01_ERROR,
370 					LIBELF_ERROR, elf_errmsg(-1),
371 					fptr->ar_pathname);
372 				else
373 					error_message(ELF_GETDATA_02_ERROR,
374 					LIBELF_ERROR, elf_errmsg(-1));
375 				num_errs++;
376 				if (newfd) {
377 					(void) close(newfd);
378 					newfd = 0;
379 				}
380 				(void) elf_end(elf);
381 				continue;
382 			}
383 			if (data->d_size == 0) {
384 				if (fptr->ar_pathname != NULL)
385 					error_message(W_ELF_NO_DATA_01_ERROR,
386 					PLAIN_ERROR, (char *)0,
387 					fptr->ar_pathname);
388 				else
389 					error_message(W_ELF_NO_DATA_02_ERROR,
390 					PLAIN_ERROR, (char *)0);
391 				if (newfd) {
392 					(void) close(newfd);
393 					newfd = 0;
394 				}
395 				(void) elf_end(elf);
396 				num_errs++;
397 				continue;
398 			}
399 			sbshstr = (char *)data->d_buf;
400 
401 			/* loop through sections to find symbol table */
402 			scn = 0;
403 			while ((scn = elf_nextscn(elf, scn)) != 0) {
404 				GElf_Shdr shdr;
405 				if (gelf_getshdr(scn, &shdr) == NULL) {
406 					if (fptr->ar_pathname != NULL)
407 						error_message(
408 						ELF_GETDATA_01_ERROR,
409 						LIBELF_ERROR, elf_errmsg(-1),
410 						fptr->ar_pathname);
411 					else
412 						error_message(
413 						ELF_GETDATA_02_ERROR,
414 						LIBELF_ERROR, elf_errmsg(-1));
415 					if (newfd) {
416 						(void) close(newfd);
417 						newfd = 0;
418 					}
419 					num_errs++;
420 					(void) elf_end(elf);
421 					continue;
422 				}
423 				*found_obj = 1;
424 				if (shdr.sh_type == SHT_SYMTAB)
425 				    if (search_sym_tab(fptr, elf,
426 						scn,
427 						&nsyms,
428 						symlist,
429 						&num_errs) == -1) {
430 					if (newfd) {
431 						(void) close(newfd);
432 						newfd = 0;
433 					}
434 					continue;
435 				    }
436 #ifdef BROWSER
437 				/*
438 				 * XX64:  sbrowser_search_stab() currently gets
439 				 *	confused by sb-tabs in v9.  at this
440 				 *	point, no one knows what v9 sb-tabs are
441 				 *	supposed to look like.
442 				 */
443 /*				if (shdr.sh_name != 0) { */
444 				if ((class == ELFCLASS32) &&
445 				    (shdr.sh_name != 0)) {
446 					sbshstrtp = (char *)
447 						((long)sbshstr + shdr.sh_name);
448 					if (strcmp(sbshstrtp, ".stab") == 0) {
449 						sbstabsect = elf_ndxscn(scn);
450 					} else if (strcmp(sbshstrtp,
451 							".stabstr") == 0) {
452 						sbstabstrsect = elf_ndxscn(scn);
453 					}
454 				}
455 #endif
456 			}
457 #ifdef BROWSER
458 			if (sbstabsect != -1 || sbstabstrsect != -1) {
459 				sbrowser_search_stab(
460 					elf,
461 					sbstabsect,
462 					sbstabstrsect,
463 					cmd_info->arnam);
464 				sbstabsect = -1;
465 				sbstabstrsect = -1;
466 			}
467 #endif
468 		}
469 		mem_offset += sizeof (struct ar_hdr) + fptr->ar_size;
470 		if (fptr->ar_size & 01)
471 			mem_offset++;
472 		(void) elf_end(elf);
473 		if (newfd) {
474 			(void) close(newfd);
475 			newfd = 0;
476 		}
477 	} /* for */
478 	if (num_errs)
479 		exit(1);
480 	return (nsyms);
481 }
482 
483 /*
484  * This routine writes an archive symbol table for the
485  * output archive file. The symbol table is built if
486  * there was at least one object file specified.
487  * In rare case, there could be no symbol.
488  * In this case, str_top and str_base can not be used to
489  * make the string table. So the routine adjust the size
490  * and make a dummy string table. String table is needed
491  * by elf_getarsym().
492  */
493 static int
494 writesymtab(char *dst, long nsyms, ARFILEP *symlist)
495 {
496 	char	buf1[sizeof (struct ar_hdr) + 1];
497 	char	*buf2, *bptr;
498 	int	i, j;
499 	ARFILEP	*ptr;
500 	long	sym_tab_size = 0;
501 	int sum = 0;
502 
503 	/*
504 	 * patch up archive pointers and write the symbol entries
505 	 */
506 	while ((str_top - str_base) & 03)	/* round up string table */
507 		*str_top++ = '\0';
508 	sym_tab_size = (nsyms +1) * 4 + sizeof (char) * (str_top - str_base);
509 	if (nsyms == 0)
510 		sym_tab_size += 4;
511 	sym_tab_size += pad_symtab;
512 
513 	(void) sprintf(buf1, FORMAT, SYMDIRNAME, time(0), (unsigned)0,
514 		(unsigned)0, (unsigned)0, (long)sym_tab_size, ARFMAG);
515 
516 	if (strlen(buf1) != sizeof (struct ar_hdr)) {
517 		error_message(INTERNAL_02_ERROR);
518 		exit(1);
519 	}
520 
521 	if ((buf2 = malloc(4 * (nsyms + 1))) == NULL) {
522 		error_message(MALLOC_ERROR);
523 		error_message(DIAG_01_ERROR, errno);
524 		exit(1);
525 	}
526 	sputl(nsyms, buf2);
527 	bptr = buf2 + 4;
528 
529 	for (i = 0, j = SYMCHUNK, ptr = symlist; i < nsyms; i++, j--, ptr++) {
530 		if (!j) {
531 			j = SYMCHUNK;
532 			ptr = (ARFILEP *)*ptr;
533 		}
534 		sputl((*ptr)->ar_offset, bptr);
535 		bptr += 4;
536 	}
537 	(void) memcpy(dst, buf1, sizeof (struct ar_hdr));
538 	dst += sizeof (struct ar_hdr);
539 	sum += sizeof (struct ar_hdr);
540 
541 	(void) memcpy(dst, buf2, (nsyms + 1) * 4);
542 	dst += (nsyms + 1)*4;
543 	sum += (nsyms + 1)*4;
544 
545 	if (nsyms != 0) {
546 		(void) memcpy(dst, str_base, (str_top - str_base));
547 		dst += str_top - str_base;
548 		sum += str_top - str_base;
549 	} else {
550 		/*
551 		 * Writing a dummy string table.
552 		 */
553 		int i;
554 		for (i = 0; i < 4; i++)
555 			*dst++ = 0;
556 		sum += 4;
557 	}
558 
559 	/*
560 	 * The first member file is ELFCLASS64. We need to make the member
561 	 * to be placed at the 8 byte boundary.
562 	 */
563 	if (pad_symtab) {
564 		int i;
565 		for (i = 0; i < 4; i++)
566 			*dst++ = 0;
567 		sum += 4;
568 	}
569 
570 	free(buf2);
571 	return (sum);
572 }
573 
574 static void
575 savename(char *symbol)
576 {
577 	static int str_length = BUFSIZ * 5;
578 	char *p, *s;
579 	unsigned int i;
580 	int diff;
581 
582 	diff = 0;
583 	if (str_base == (char *)0) {
584 		/* no space allocated yet */
585 		if ((str_base = malloc((unsigned)str_length))
586 		    == NULL) {
587 			error_message(MALLOC_ERROR,
588 			PLAIN_ERROR, (char *)0);
589 			exit(1);
590 		}
591 		str_top = str_base;
592 	}
593 
594 	p = str_top;
595 	str_top += strlen(symbol) + 1;
596 
597 	if (str_top > str_base + str_length) {
598 		char *old_base = str_base;
599 
600 		do
601 			str_length += BUFSIZ * 2;
602 		while (str_top > str_base + str_length);
603 		if ((str_base = (char *)realloc(str_base, str_length)) ==
604 		    NULL) {
605 			error_message(MALLOC_ERROR,
606 			PLAIN_ERROR, (char *)0);
607 			exit(1);
608 		}
609 		/*
610 		 * Re-adjust other pointers
611 		 */
612 		diff = str_base - old_base;
613 		p += diff;
614 	}
615 	for (i = 0, s = symbol;
616 		i < strlen(symbol) && *s != '\0'; i++) {
617 		*p++ = *s++;
618 	}
619 	*p++ = '\0';
620 	str_top = p;
621 }
622 
623 static void
624 savelongname(ARFILE *fptr, char *ptr_index)
625 {
626 	static int str_length = BUFSIZ * 5;
627 	char *p, *s;
628 	unsigned int i;
629 	int diff;
630 	static int bytes_used;
631 	int index;
632 	char	ptr_index1[SNAME-1];
633 
634 	diff = 0;
635 	if (str_base1 == (char *)0) {
636 		/* no space allocated yet */
637 		if ((str_base1 = malloc((unsigned)str_length))
638 		    == NULL) {
639 			error_message(MALLOC_ERROR,
640 			PLAIN_ERROR, (char *)0);
641 			exit(1);
642 		}
643 		str_top1 = str_base1;
644 	}
645 
646 	p = str_top1;
647 	str_top1 += strlen(fptr->ar_longname) + 2;
648 
649 	index = bytes_used;
650 	(void) sprintf(ptr_index1, "%d", index); /* holds digits */
651 	(void) sprintf(ptr_index, FNFORMAT, SYMDIRNAME);
652 	ptr_index[1] = '\0';
653 	(void) strcat(ptr_index, ptr_index1);
654 	(void) strcpy(fptr->ar_name, ptr_index);
655 	bytes_used += strlen(fptr->ar_longname) + 2;
656 
657 	if (str_top1 > str_base1 + str_length) {
658 		char *old_base = str_base1;
659 
660 		do
661 			str_length += BUFSIZ * 2;
662 		while (str_top1 > str_base1 + str_length);
663 		if ((str_base1 = (char *)realloc(str_base1, str_length))
664 		    == NULL) {
665 			error_message(MALLOC_ERROR,
666 			PLAIN_ERROR, (char *)0);
667 			exit(1);
668 		}
669 		/*
670 		 * Re-adjust other pointers
671 		 */
672 		diff = str_base1 - old_base;
673 		p += diff;
674 	}
675 	for (i = 0, s = fptr->ar_longname;
676 		i < strlen(fptr->ar_longname) && *s != '\0';
677 		i++) {
678 		*p++ = *s++;
679 	}
680 	*p++ = '/';
681 	*p++ = '\n';
682 	str_top1 = p;
683 }
684 
685 char *
686 writefile(Cmd_info *cmd_info)
687 {
688 	ARFILE	* fptr;
689 	ARFILEP *symlist = 0;
690 	int i;
691 	int longnames = 0;
692 	long long_tab_size = 0;
693 	long nsyms;
694 	int new_archive = 0;
695 	char *name = cmd_info->arnam;
696 	int arsize;
697 	char *dst;
698 	char *tmp_dst;
699 	int nfd;
700 	int found_obj = 0;
701 
702 	long_tab_size = mklong_tab(&longnames);
703 	nsyms = mksymtab(&symlist, cmd_info, &found_obj);
704 
705 	for (i = 0; signum[i]; i++)
706 		/* started writing, cannot interrupt */
707 		(void) signal(signum[i], SIG_IGN);
708 
709 
710 	/* Is this a new archive? */
711 	if ((access(cmd_info->arnam,  0)  < 0) && (errno == ENOENT)) {
712 	    new_archive = 1;
713 	    if (!opt_FLAG(cmd_info, c_FLAG)) {
714 		error_message(BER_MES_CREATE_ERROR,
715 		PLAIN_ERROR, (char *)0, cmd_info->arnam);
716 	    }
717 	}
718 	else
719 	    new_archive = 0;
720 
721 	/*
722 	 * Calculate the size of the new archive
723 	 */
724 	arsize = sizeofnewarchive(nsyms, longnames);
725 
726 	/*
727 	 * Dummy symtab ?
728 	 */
729 	if (nsyms == 0 && found_obj != 0)
730 		/*
731 		 * 4 + 4 = First 4 bytes to keep the number of symbols.
732 		 *	   The second 4 bytes for string table.
733 		 */
734 		arsize += sizeof (struct ar_hdr) + 4 + 4;
735 
736 	if (arsize > AR_MAX_BYTES_IN_MEM) {
737 		tmp_dst = dst = NULL;
738 	} else {
739 		tmp_dst = dst = malloc(arsize);
740 	}
741 	if (dst == NULL) {
742 		return writelargefile(cmd_info, long_tab_size,
743 			longnames, symlist, nsyms, found_obj, new_archive);
744 	}
745 
746 	(void) memcpy(tmp_dst, ARMAG, SARMAG);
747 	tmp_dst += SARMAG;
748 
749 	if (nsyms || found_obj != 0) {
750 		int diff;
751 		diff = writesymtab(tmp_dst, nsyms, symlist);
752 		tmp_dst += diff;
753 	}
754 
755 	if (longnames) {
756 		(void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0),
757 			(unsigned)0, (unsigned)0, (unsigned)0,
758 			(long)long_tab_size, ARFMAG);
759 		tmp_dst += sizeof (struct ar_hdr);
760 		(void) memcpy(tmp_dst, str_base1, str_top1 - str_base1);
761 		tmp_dst += str_top1 - str_base1;
762 	}
763 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
764 
765 	/*
766 	 * NOTE:
767 	 *	The mem_header->ar_name[] is set to a NULL string
768 	 *	if the archive member header has some error.
769 	 *	(See elf_getarhdr() man page.)
770 	 *	It is set to NULL for example, the ar command reads
771 	 *	the archive files created by SunOS 4.1 system.
772 	 *	See c block comment in cmd.c, "Incompatible Archive Header".
773 	 */
774 		if (fptr->ar_name[0] == 0) {
775 			fptr->ar_longname = fptr->ar_rawname;
776 			(void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
777 		}
778 		if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2)
779 			(void) sprintf(tmp_dst, FNFORMAT,
780 					trimslash(fptr->ar_longname));
781 		else
782 			(void) sprintf(tmp_dst, FNFORMAT, fptr->ar_name);
783 		(void) sprintf(tmp_dst+16, TLFORMAT, fptr->ar_date,
784 		    (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid,
785 		    (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding,
786 		    ARFMAG);
787 
788 		tmp_dst += sizeof (struct ar_hdr);
789 
790 		if (!(fptr->ar_flag & F_MALLOCED) &&
791 		    !(fptr->ar_flag & F_MMAPED) &&
792 		    !(fptr->ar_flag & F_ELFRAW)) {
793 		/* file was not read in fptr->ar_contents during 'cmd' */
794 		/* do it now */
795 			FILE *f;
796 			f = fopen(fptr->ar_pathname, "r");
797 			if (f == NULL) {
798 				error_message(SYS_OPEN_ERROR,
799 				    SYSTEM_ERROR, strerror(errno),
800 				    fptr->ar_longname);
801 				exit(1);
802 			} else {
803 				if (fread(tmp_dst,
804 				    sizeof (char),
805 				    fptr->ar_size, f) != fptr->ar_size) {
806 					error_message(SYS_READ_ERROR,
807 					SYSTEM_ERROR, strerror(errno),
808 					fptr->ar_longname);
809 					exit(1);
810 				}
811 			}
812 			(void) fclose(f);
813 		} else {
814 			(void) memcpy(tmp_dst, fptr->ar_contents,
815 				fptr->ar_size);
816 			if (fptr->ar_flag & F_MALLOCED) {
817 				(void) free(fptr->ar_contents);
818 				fptr->ar_flag &= ~(F_MALLOCED);
819 			}
820 		}
821 		tmp_dst += fptr->ar_size;
822 
823 		if (fptr->ar_size & 0x1) {
824 			(void) memcpy(tmp_dst, "\n", 1);
825 			tmp_dst++;
826 		}
827 
828 		if (fptr->ar_padding) {
829 			int i = fptr->ar_padding;
830 			while (i) {
831 				*tmp_dst++ = '\n';
832 				--i;
833 			}
834 		}
835 	}
836 
837 	/*
838 	 * All preparation for writing is done.
839 	 */
840 	(void) elf_end(cmd_info->arf);
841 	(void) close(cmd_info->afd);
842 
843 	/*
844 	 * Write out to the file
845 	 */
846 	if (new_archive) {
847 		/*
848 		 * create a new file
849 		 */
850 		nfd = creat(name, 0666);
851 		if (nfd == -1) {
852 			error_message(SYS_CREATE_01_ERROR,
853 			SYSTEM_ERROR, strerror(errno), name);
854 			exit(1);
855 		}
856 	} else {
857 		/*
858 		 * Open the new file
859 		 */
860 		nfd = open(name, O_RDWR|O_TRUNC);
861 		if (nfd == -1) {
862 			error_message(SYS_WRITE_02_ERROR,
863 			SYSTEM_ERROR, strerror(errno), name);
864 			exit(1);
865 		}
866 	}
867 #ifndef XPG4
868 	if (opt_FLAG(cmd_info, v_FLAG)) {
869 	    error_message(BER_MES_WRITE_ERROR,
870 	    PLAIN_ERROR, (char *)0,
871 	    cmd_info->arnam);
872 	}
873 #endif
874 	if (write(nfd, dst, arsize) != arsize) {
875 		error_message(SYS_WRITE_04_ERROR,
876 			SYSTEM_ERROR, strerror(errno), name);
877 		if (!new_archive)
878 			error_message(WARN_USER_ERROR,
879 			PLAIN_ERROR, (char *)0);
880 		exit(2);
881 	}
882 	return (dst);
883 }
884 
885 static long
886 mklong_tab(int *longnames)
887 {
888 	ARFILE  *fptr;
889 	char ptr_index[SNAME+1];
890 	long ret = 0;
891 
892 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
893 		if (strlen(fptr->ar_longname) >= (unsigned)SNAME-1) {
894 			(*longnames)++;
895 			savelongname(fptr, ptr_index);
896 			(void) strcpy(fptr->ar_name, ptr_index);
897 		}
898 	}
899 	if (*longnames) {
900 		/* round up table that keeps the long filenames */
901 		while ((str_top1 - str_base1) & 03)
902 			*str_top1++ = '\n';
903 		ret = sizeof (char) * (str_top1 - str_base1);
904 	}
905 	return (ret);
906 }
907 
908 /* Put bytes in archive header in machine independent order.  */
909 
910 static void
911 sputl(long n, char *cp)
912 {
913 	*cp++ = n >> 24;
914 	*cp++ = n >> 16;
915 	*cp++ = n >> 8;
916 
917 	*cp++ = n & 255;
918 }
919 
920 #ifdef BROWSER
921 
922 static void
923 sbrowser_search_stab(Elf *elf, int stabid, int stabstrid, char *arnam)
924 {
925 	Elf_Scn		*stab_scn;
926 	Elf_Scn		*stabstr_scn;
927 	Elf_Data	*data;
928 	struct nlist	*np;
929 	struct nlist	*stabtab;
930 	char		*stabstrtab;
931 	char		*stabstroff;
932 	char		*symname;
933 	int		prevstabstrsz;
934 	GElf_Xword	nstab;
935 	GElf_Shdr	shdr;
936 
937 	/* use the .stab and stabstr section index to find the data buffer */
938 	if (stabid == -1) {
939 		error_message(SBROW_01_ERROR,
940 		PLAIN_ERROR, (char *)0);
941 		return;
942 	}
943 	stab_scn = elf_getscn(elf, (size_t)stabid);
944 	if (stab_scn == NULL) {
945 		error_message(ELF_GETDATA_02_ERROR,
946 		LIBELF_ERROR, elf_errmsg(-1));
947 		return;
948 	}
949 
950 	(void) gelf_getshdr(stab_scn, &shdr);
951 	/*
952 	 * Zero length .stab sections have been produced by some compilers so
953 	 * ignore the section if this is the case.
954 	 */
955 	if ((nstab = shdr.sh_size / shdr.sh_entsize) == 0)
956 		return;
957 
958 	if (stabstrid == -1) {
959 		error_message(SBROW_02_ERROR,
960 		PLAIN_ERROR, (char *)0);
961 		return;
962 	}
963 	stabstr_scn = elf_getscn(elf, (size_t)stabstrid);
964 	if (stabstr_scn == NULL) {
965 		error_message(ELF_GETDATA_02_ERROR,
966 		LIBELF_ERROR, elf_errmsg(-1));
967 		return;
968 	}
969 	if (gelf_getshdr(stabstr_scn, &shdr) == NULL) {
970 		error_message(ELF_GETDATA_02_ERROR,
971 		LIBELF_ERROR, elf_errmsg(-1));
972 		return;
973 	}
974 	if (shdr.sh_size == 0) {
975 		error_message(SBROW_03_ERROR,
976 		PLAIN_ERROR, (char *)0);
977 		return;
978 	}
979 
980 	data = 0;
981 	data = elf_getdata(stabstr_scn, data);
982 	if (data == NULL) {
983 		error_message(ELF_GETDATA_02_ERROR,
984 		LIBELF_ERROR, elf_errmsg(-1));
985 		return;
986 	}
987 	if (data->d_size == 0) {
988 		error_message(SBROW_02_ERROR,
989 		PLAIN_ERROR, (char *)0);
990 		return;
991 	}
992 	stabstrtab = (char *)data->d_buf;
993 	data = 0;
994 	data = elf_getdata(stab_scn, data);
995 	if (data == NULL) {
996 		error_message(ELF_GETDATA_02_ERROR,
997 		LIBELF_ERROR, elf_errmsg(-1));
998 		return;
999 	}
1000 	if (data->d_size == 0) {
1001 		error_message(SBROW_03_ERROR,
1002 		PLAIN_ERROR, (char *)0);
1003 		return;
1004 	}
1005 	stabtab = (struct nlist *)data->d_buf;
1006 	stabstroff = stabstrtab;
1007 	prevstabstrsz = 0;
1008 	for (np = stabtab; np < &stabtab[nstab]; np++) {
1009 		if (np->n_type == 0) {
1010 			stabstroff += prevstabstrsz;
1011 			prevstabstrsz = np->n_value;
1012 		}
1013 		symname = stabstroff + np->n_un.n_strx;
1014 		if (np->n_type == 0x48) {
1015 			sbfocus_symbol(&sb_data, arnam, "-a", symname);
1016 		}
1017 	}
1018 }
1019 #endif
1020 
1021 
1022 
1023 static int
1024 search_sym_tab(ARFILE *fptr, Elf *elf, Elf_Scn *scn,
1025 	long *nsyms, ARFILEP **symlist, int *num_errs)
1026 {
1027 	Elf_Data *str_data, *sym_data; /* string table, symbol table */
1028 	Elf_Scn *str_scn;
1029 	GElf_Sxword no_of_symbols;
1030 	GElf_Shdr shdr;
1031 	int counter;
1032 	int str_shtype;
1033 	char *symname;
1034 	static ARFILEP *sym_ptr = 0;
1035 	static ARFILEP *nextsym = NULL;
1036 	static int syms_left = 0;
1037 	char *fname = fptr->ar_pathname;
1038 
1039 	(void) gelf_getshdr(scn, &shdr);
1040 	str_scn = elf_getscn(elf, shdr.sh_link); /* index for string table */
1041 	if (str_scn == NULL) {
1042 		if (fname != NULL)
1043 			error_message(ELF_GETDATA_01_ERROR,
1044 			LIBELF_ERROR, elf_errmsg(-1),
1045 			fname);
1046 		else
1047 			error_message(ELF_GETDATA_02_ERROR,
1048 			LIBELF_ERROR, elf_errmsg(-1));
1049 		(*num_errs)++;
1050 		return (-1);
1051 	}
1052 
1053 	no_of_symbols = shdr.sh_size / shdr.sh_entsize;
1054 	if (no_of_symbols == -1) {
1055 		error_message(SYMTAB_01_ERROR,
1056 		PLAIN_ERROR, (char *)0);
1057 		return (-1);
1058 	}
1059 
1060 	(void) gelf_getshdr(str_scn, &shdr);
1061 	str_shtype = shdr.sh_type;
1062 	if (str_shtype == -1) {
1063 		if (fname != NULL)
1064 			error_message(ELF_GETDATA_01_ERROR,
1065 			LIBELF_ERROR, elf_errmsg(-1), fname);
1066 		else
1067 			error_message(ELF_GETDATA_02_ERROR,
1068 			LIBELF_ERROR, elf_errmsg(-1));
1069 		(*num_errs)++;
1070 		return (-1);
1071 	}
1072 
1073 	/* This test must happen before testing the string table. */
1074 	if (no_of_symbols == 1)
1075 		return (0);	/* no symbols; 0th symbol is the non-symbol */
1076 
1077 	if (str_shtype != SHT_STRTAB) {
1078 		if (fname != NULL)
1079 			error_message(SYMTAB_02_ERROR,
1080 			PLAIN_ERROR, (char *)0,
1081 			fname);
1082 		else
1083 			error_message(SYMTAB_03_ERROR,
1084 			PLAIN_ERROR, (char *)0);
1085 		return (0);
1086 	}
1087 	str_data = 0;
1088 	if ((str_data = elf_getdata(str_scn, str_data)) == 0) {
1089 		if (fname != NULL)
1090 			error_message(SYMTAB_04_ERROR,
1091 			PLAIN_ERROR, (char *)0,
1092 			fname);
1093 		else
1094 			error_message(SYMTAB_05_ERROR,
1095 			PLAIN_ERROR, (char *)0);
1096 		return (0);
1097 	}
1098 	if (str_data->d_size == 0) {
1099 		if (fname != NULL)
1100 			error_message(SYMTAB_06_ERROR,
1101 			PLAIN_ERROR, (char *)0,
1102 			fname);
1103 		else
1104 			error_message(SYMTAB_07_ERROR,
1105 			PLAIN_ERROR, (char *)0);
1106 		return (0);
1107 	}
1108 	sym_data = 0;
1109 	if ((sym_data = elf_getdata(scn, sym_data)) == NULL) {
1110 		if (fname != NULL)
1111 			error_message(ELF_01_ERROR,
1112 			LIBELF_ERROR, elf_errmsg(-1),
1113 			fname, elf_errmsg(-1));
1114 		else
1115 			error_message(ELF_02_ERROR,
1116 			LIBELF_ERROR, elf_errmsg(-1),
1117 			elf_errmsg(-1));
1118 		return (0);
1119 	}
1120 
1121 	/* start at 1, first symbol entry is ignored */
1122 	for (counter = 1; counter < no_of_symbols; counter++) {
1123 		GElf_Sym sym;
1124 		(void) gelf_getsym(sym_data, counter, &sym);
1125 
1126 		symname = (char *)(str_data->d_buf) + sym.st_name;
1127 
1128 		if (((GELF_ST_BIND(sym.st_info) == STB_GLOBAL) ||
1129 			(GELF_ST_BIND(sym.st_info) == STB_WEAK)) &&
1130 			(sym.st_shndx != SHN_UNDEF)) {
1131 			if (!syms_left) {
1132 				sym_ptr = malloc((SYMCHUNK+1)
1133 						* sizeof (ARFILEP));
1134 				if (sym_ptr == NULL) {
1135 					error_message(MALLOC_ERROR,
1136 					PLAIN_ERROR, (char *)0);
1137 					exit(1);
1138 				}
1139 				syms_left = SYMCHUNK;
1140 				if (nextsym)
1141 					*nextsym = (ARFILEP)sym_ptr;
1142 				else
1143 					*symlist = sym_ptr;
1144 				nextsym = sym_ptr;
1145 			}
1146 			sym_ptr = nextsym;
1147 			nextsym++;
1148 			syms_left--;
1149 			(*nsyms)++;
1150 			*sym_ptr = fptr;
1151 			savename(symname);	/* put name in the archiver's */
1152 						/* symbol table string table */
1153 		}
1154 	}
1155 	return (0);
1156 }
1157 
1158 /*
1159  * Get the output file size
1160  */
1161 static int
1162 sizeofmembers(int psum)
1163 {
1164 	int sum = 0;
1165 	ARFILE *fptr;
1166 	int hdrsize = sizeof (struct ar_hdr);
1167 
1168 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1169 		fptr->ar_offset = psum + sum;
1170 		sum += fptr->ar_size;
1171 		if (fptr->ar_size & 01)
1172 			sum++;
1173 		sum += hdrsize;
1174 
1175 		if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) &&
1176 		    fptr->ar_next && (fptr->ar_next->ar_flag & F_CLASS64)) {
1177 			int remainder;
1178 
1179 			remainder = (psum + sum + hdrsize) % 8;
1180 			if (remainder) {
1181 				sum += (8 - remainder);
1182 				fptr->ar_padding = 8 - remainder;
1183 			}
1184 		}
1185 	}
1186 	return (sum);
1187 }
1188 
1189 static int
1190 sizeofnewarchive(int nsyms, int longnames)
1191 {
1192 	int sum = 0;
1193 
1194 	sum += SARMAG;
1195 
1196 	if (nsyms) {
1197 		char *top = (char *)str_top;
1198 		char *base = (char *)str_base;
1199 
1200 		while ((top - base) & 03)
1201 			top++;
1202 		sum += sizeof (struct ar_hdr);
1203 		sum += (nsyms + 1) * 4;
1204 		sum += top - base;
1205 	}
1206 
1207 	if (longnames) {
1208 		sum += sizeof (struct ar_hdr);
1209 		sum += str_top1 - str_base1;
1210 	}
1211 
1212 	/*
1213 	 * If the first member file is ELFCLASS64 type,
1214 	 * we have to ensure the member contents will align
1215 	 * on 8 byte boundary.
1216 	 */
1217 	if (listhead && (listhead->ar_flag & F_CLASS64)) {
1218 		if (((sum + (sizeof (struct ar_hdr))) % 8) != 0) {
1219 			sum += 4;
1220 			pad_symtab = 4;
1221 		}
1222 	}
1223 	sum += sizeofmembers(sum);
1224 	return (sum);
1225 }
1226 
1227 static void
1228 arwrite(char *name, int nfd, char *dst, int size) {
1229 	if (write(nfd, dst, size) != size) {
1230 		error_message(SYS_WRITE_04_ERROR,
1231 			SYSTEM_ERROR, strerror(errno), name);
1232 		exit(2);
1233 	}
1234 }
1235 
1236 static char *
1237 make_tmpname(char *filename) {
1238 	static char template[] = "arXXXXXX";
1239 	char *tmpname;
1240 	char *slash = strrchr(filename, '/');
1241 
1242 	if (slash != (char *)NULL) {
1243 		char c;
1244 
1245 		c = *slash;
1246 		*slash = 0;
1247 		tmpname = (char *)malloc(strlen(filename) +
1248 			sizeof (template) + 2);
1249 		(void) strcpy(tmpname, filename);
1250 		(void) strcat(tmpname, "/");
1251 		(void) strcat(tmpname, template);
1252 		(void) mktemp(tmpname);
1253 		*slash = c;
1254 	} else {
1255 		tmpname = malloc(sizeof (template));
1256 		(void) strcpy(tmpname, template);
1257 		(void) mktemp(tmpname);
1258 	}
1259 	return (tmpname);
1260 }
1261 
1262 static int
1263 ar_copy(char *from, char *to) {
1264 	int fromfd, tofd, nread;
1265 	int saved;
1266 	char buf[8192];
1267 
1268 	fromfd = open(from, O_RDONLY);
1269 	if (fromfd < 0)
1270 		return (-1);
1271 	tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC, 0777);
1272 	if (tofd < 0) {
1273 		saved = errno;
1274 		(void) close(fromfd);
1275 		errno = saved;
1276 		return (-1);
1277 	}
1278 	while ((nread = read(fromfd, buf, sizeof (buf))) > 0) {
1279 		if (write(tofd, buf, nread) != nread) {
1280 			saved = errno;
1281 			(void) close(fromfd);
1282 			(void) close(tofd);
1283 			errno = saved;
1284 			return (-1);
1285 		}
1286 	}
1287 	saved = errno;
1288 	(void) close(fromfd);
1289 	(void) close(tofd);
1290 	if (nread < 0) {
1291 		errno = saved;
1292 		return (-1);
1293 	}
1294 	return (0);
1295 }
1296 
1297 static int
1298 ar_rename(char *from, char *to)
1299 {
1300 	int exists;
1301 	struct stat s;
1302 	int ret = 0;
1303 
1304 	exists = lstat(to, &s) == 0;
1305 
1306 	if (! exists || (!S_ISLNK(s.st_mode) && s.st_nlink == 1)) {
1307 		ret = rename(from, to);
1308 		if (ret == 0) {
1309 			if (exists) {
1310 				(void) chmod(to, s.st_mode & 0777);
1311 				if (chown(to, s.st_uid, s.st_gid) >= 0)
1312 					(void) chmod(to, s.st_mode & 07777);
1313 				}
1314 		} else {
1315 			(void) unlink(from);
1316 		}
1317 	} else {
1318 		ret = ar_copy(from, to);
1319 		(void) unlink(from);
1320 	}
1321 	return (ret);
1322 }
1323 
1324 static int
1325 sizeofnewarchiveheader(int nsyms, int longnames)
1326 {
1327 	int sum = 0;
1328 
1329 	sum += SARMAG;
1330 
1331 	if (nsyms) {
1332 		char *top = (char *)str_top;
1333 		char *base = (char *)str_base;
1334 
1335 		while ((top - base) & 03)
1336 			top++;
1337 		sum += sizeof (struct ar_hdr);
1338 		sum += (nsyms + 1) * 4;
1339 		sum += top - base;
1340 	}
1341 
1342 	if (longnames) {
1343 		sum += sizeof (struct ar_hdr);
1344 		sum += str_top1 - str_base1;
1345 	}
1346 
1347 	/*
1348 	 * If the first member file is ELFCLASS64 type,
1349 	 * we have to ensure the member contents will align
1350 	 * on 8 byte boundary.
1351 	 */
1352 	if (listhead && (listhead->ar_flag & F_CLASS64)) {
1353 		if (((sum + (sizeof (struct ar_hdr))) % 8) != 0) {
1354 			sum += 4;
1355 		}
1356 	}
1357 	return (sum);
1358 }
1359 
1360 static char *
1361 writelargefile(Cmd_info *cmd_info, long long_tab_size, int longnames,
1362 	ARFILEP *symlist, long nsyms, int found_obj, int new_archive)
1363 {
1364 	ARFILE	* fptr;
1365 	char *name = cmd_info->arnam;
1366 	int arsize;
1367 	char *dst;
1368 	char *tmp_dst;
1369 	int nfd;
1370 	char  *new_name;
1371 	FILE *f;
1372 	struct stat stbuf;
1373 
1374 	new_name = make_tmpname(name);
1375 
1376 	if (new_archive) {
1377 		nfd = open(name, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
1378 		if (nfd == -1) {
1379 			error_message(SYS_CREATE_01_ERROR,
1380 			SYSTEM_ERROR, strerror(errno), name);
1381 			exit(1);
1382 		}
1383 	} else {
1384 		nfd = open(new_name, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
1385 		if (nfd == -1) {
1386 			error_message(SYS_WRITE_02_ERROR,
1387 			SYSTEM_ERROR, strerror(errno), name);
1388 			exit(1);
1389 		}
1390 	}
1391 
1392 	arsize = sizeofnewarchiveheader(nsyms, longnames);
1393 	if (nsyms == 0 && found_obj != 0)
1394 		arsize += sizeof (struct ar_hdr) + 4 + 4;
1395 	if (arsize < 2048) {
1396 		arsize = 2048;
1397 	}
1398 	dst = tmp_dst = (char *)malloc(arsize);
1399 	(void) memcpy(tmp_dst, ARMAG, SARMAG);
1400 	tmp_dst += SARMAG;
1401 
1402 	if (nsyms || found_obj != 0) {
1403 		int diff;
1404 		diff = writesymtab(tmp_dst, nsyms, symlist);
1405 		tmp_dst += diff;
1406 	}
1407 
1408 	if (longnames) {
1409 		(void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0),
1410 			(unsigned)0, (unsigned)0, (unsigned)0,
1411 			(long)long_tab_size, ARFMAG);
1412 		tmp_dst += sizeof (struct ar_hdr);
1413 		(void) memcpy(tmp_dst, str_base1, str_top1 - str_base1);
1414 		tmp_dst += str_top1 - str_base1;
1415 	}
1416 #ifndef XPG4
1417 	if (opt_FLAG(cmd_info, v_FLAG)) {
1418 	    error_message(BER_MES_WRITE_ERROR,
1419 	    PLAIN_ERROR, (char *)0,
1420 	    cmd_info->arnam);
1421 	}
1422 #endif
1423 	arwrite(name, nfd, dst, (int)(tmp_dst - dst));
1424 
1425 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1426 		if (fptr->ar_name[0] == 0) {
1427 			fptr->ar_longname = fptr->ar_rawname;
1428 			(void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
1429 		}
1430 		if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2)
1431 			(void) sprintf(dst, FNFORMAT,
1432 					trimslash(fptr->ar_longname));
1433 		else
1434 			(void) sprintf(dst, FNFORMAT, fptr->ar_name);
1435 		(void) sprintf(dst+16, TLFORMAT, fptr->ar_date,
1436 		    (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid,
1437 		    (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding,
1438 		    ARFMAG);
1439 		arwrite(name, nfd, dst, sizeof (struct ar_hdr));
1440 
1441 		if (!(fptr->ar_flag & F_MALLOCED) &&
1442 		    !(fptr->ar_flag & F_MMAPED) &&
1443 		    !(fptr->ar_flag & F_ELFRAW)) {
1444 			f = fopen(fptr->ar_pathname, "r");
1445 			if (stat(fptr->ar_pathname, &stbuf) < 0) {
1446 				(void) fclose(f);
1447 				f = NULL;
1448 			}
1449 			if (f == NULL) {
1450 				error_message(SYS_OPEN_ERROR,
1451 				SYSTEM_ERROR, strerror(errno),
1452 				fptr->ar_longname);
1453 				exit(1);
1454 			} else {
1455 				if ((fptr->ar_contents = (char *)
1456 				    malloc(ROUNDUP(stbuf.st_size))) == NULL) {
1457 					error_message(MALLOC_ERROR,
1458 					PLAIN_ERROR, (char *)0);
1459 					exit(1);
1460 				}
1461 				if (fread(fptr->ar_contents,
1462 				    sizeof (char),
1463 				    stbuf.st_size, f) != stbuf.st_size) {
1464 					error_message(SYS_READ_ERROR,
1465 					SYSTEM_ERROR, strerror(errno),
1466 					fptr->ar_longname);
1467 					exit(1);
1468 				}
1469 			}
1470 			arwrite(name, nfd, fptr->ar_contents, fptr->ar_size);
1471 			(void) fclose(f);
1472 			free(fptr->ar_contents);
1473 		} else {
1474 			arwrite(name, nfd, fptr->ar_contents, fptr->ar_size);
1475 			if (fptr->ar_flag & F_MALLOCED) {
1476 				(void) free(fptr->ar_contents);
1477 				fptr->ar_flag &= ~(F_MALLOCED);
1478 			}
1479 		}
1480 
1481 		if (fptr->ar_size & 0x1) {
1482 			arwrite(name, nfd, "\n", 1);
1483 		}
1484 
1485 		if (fptr->ar_padding) {
1486 			int i = fptr->ar_padding;
1487 			while (i) {
1488 				arwrite(name, nfd, "\n", 1);
1489 				--i;
1490 			}
1491 		}
1492 	}
1493 
1494 	/*
1495 	 * All preparation for writing is done.
1496 	 */
1497 	(void) elf_end(cmd_info->arf);
1498 	(void) close(cmd_info->afd);
1499 
1500 	if (!new_archive) {
1501 		(void) ar_rename(new_name, name);
1502 	}
1503 
1504 	return (dst);
1505 }
1506