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