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