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