1 /* Create, modify, and extract from archives.
2 Copyright (C) 2005-2012, 2016, 2017 Red Hat, Inc.
3 This file is part of elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2005.
5
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 elfutils is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <argp.h>
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <gelf.h>
27 #include <libintl.h>
28 #include <limits.h>
29 #include <locale.h>
30 #include <search.h>
31 #include <stdbool.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stdio_ext.h>
35 #include <string.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41
42 #include <system.h>
43 #include <printversion.h>
44
45 #include "arlib.h"
46
47
48 /* Name and version of program. */
49 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
50
51 /* Prototypes for local functions. */
52 static int do_oper_extract (int oper, const char *arfname, char **argv,
53 int argc, long int instance);
54 static int do_oper_delete (const char *arfname, char **argv, int argc,
55 long int instance);
56 static int do_oper_insert (int oper, const char *arfname, char **argv,
57 int argc, const char *member);
58
59
60 /* Bug report address. */
61 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
62
63
64 /* Definitions of arguments for argp functions. */
65 static const struct argp_option options[] =
66 {
67 { NULL, 0, NULL, 0, N_("Commands:"), 1 },
68 { NULL, 'd', NULL, 0, N_("Delete files from archive."), 0 },
69 { NULL, 'm', NULL, 0, N_("Move files in archive."), 0 },
70 { NULL, 'p', NULL, 0, N_("Print files in archive."), 0 },
71 { NULL, 'q', NULL, 0, N_("Quick append files to archive."), 0 },
72 { NULL, 'r', NULL, 0,
73 N_("Replace existing or insert new file into archive."), 0 },
74 { NULL, 't', NULL, 0, N_("Display content of archive."), 0 },
75 { NULL, 'x', NULL, 0, N_("Extract files from archive."), 0 },
76
77 { NULL, 0, NULL, 0, N_("Command Modifiers:"), 2 },
78 { NULL, 'o', NULL, 0, N_("Preserve original dates."), 0 },
79 { NULL, 'N', NULL, 0, N_("Use instance [COUNT] of name."), 0 },
80 { NULL, 'C', NULL, 0,
81 N_("Do not replace existing files with extracted files."), 0 },
82 { NULL, 'T', NULL, 0, N_("Allow filename to be truncated if necessary."),
83 0 },
84 { NULL, 'v', NULL, 0, N_("Provide verbose output."), 0 },
85 { NULL, 's', NULL, 0, N_("Force regeneration of symbol table."), 0 },
86 { NULL, 'a', NULL, 0, N_("Insert file after [MEMBER]."), 0 },
87 { NULL, 'b', NULL, 0, N_("Insert file before [MEMBER]."), 0 },
88 { NULL, 'i', NULL, 0, N_("Same as -b."), 0 },
89 { NULL, 'c', NULL, 0, N_("Suppress message when library has to be created."),
90 0 },
91 { NULL, 'P', NULL, 0, N_("Use full path for file matching."), 0 },
92 { NULL, 'u', NULL, 0, N_("Update only older files in archive."), 0 },
93
94 { NULL, 0, NULL, 0, NULL, 0 }
95 };
96
97 /* Short description of program. */
98 static const char doc[] = N_("Create, modify, and extract from archives.");
99
100 /* Strings for arguments in help texts. */
101 static const char args_doc[] = N_("[MEMBER] [COUNT] ARCHIVE [FILE...]");
102
103 /* Prototype for option handler. */
104 static error_t parse_opt (int key, char *arg, struct argp_state *state);
105
106 /* Data structure to communicate with argp functions. */
107 static struct argp argp =
108 {
109 options, parse_opt, args_doc, doc, arlib_argp_children, NULL, NULL
110 };
111
112
113 /* What operation to perform. */
114 static enum
115 {
116 oper_none,
117 oper_delete,
118 oper_move,
119 oper_print,
120 oper_qappend,
121 oper_replace,
122 oper_list,
123 oper_extract
124 } operation;
125
126 /* Modifiers. */
127 static bool verbose;
128 static bool preserve_dates;
129 static bool instance_specifed;
130 static bool dont_replace_existing;
131 static bool allow_truncate_fname;
132 static bool force_symtab;
133 static bool suppress_create_msg;
134 static bool full_path;
135 static bool update_newer;
136 static enum { ipos_none, ipos_before, ipos_after } ipos;
137
138
139 int
main(int argc,char * argv[])140 main (int argc, char *argv[])
141 {
142 /* We use no threads here which can interfere with handling a stream. */
143 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
144 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
145 (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
146
147 /* Set locale. */
148 (void) setlocale (LC_ALL, "");
149
150 /* Make sure the message catalog can be found. */
151 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
152
153 /* Initialize the message catalog. */
154 (void) textdomain (PACKAGE_TARNAME);
155
156 /* For historical reasons the options in the first parameter need
157 not be preceded by a dash. Add it now if necessary. */
158 if (argc > 1 && argv[1][0] != '-')
159 {
160 size_t len = strlen (argv[1]) + 1;
161 char *newp = alloca (len + 1);
162 newp[0] = '-';
163 memcpy (&newp[1], argv[1], len);
164 argv[1] = newp;
165 }
166
167 /* Parse and process arguments. */
168 int remaining;
169 (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL);
170
171 /* Tell the library which version we are expecting. */
172 (void) elf_version (EV_CURRENT);
173
174 /* Handle the [MEMBER] parameter. */
175 const char *member = NULL;
176 if (ipos != ipos_none)
177 {
178 /* Only valid for certain operations. */
179 if (operation != oper_move && operation != oper_replace)
180 error (1, 0, _("\
181 'a', 'b', and 'i' are only allowed with the 'm' and 'r' options"));
182
183 if (remaining == argc)
184 {
185 error (0, 0, _("\
186 MEMBER parameter required for 'a', 'b', and 'i' modifiers"));
187 argp_help (&argp, stderr, ARGP_HELP_USAGE | ARGP_HELP_SEE,
188 program_invocation_short_name);
189 exit (EXIT_FAILURE);
190 }
191
192 member = argv[remaining++];
193 }
194
195 /* Handle the [COUNT] parameter. */
196 long int instance = -1;
197 if (instance_specifed)
198 {
199 /* Only valid for certain operations. */
200 if (operation != oper_extract && operation != oper_delete)
201 error (1, 0, _("\
202 'N' is only meaningful with the 'x' and 'd' options"));
203
204 if (remaining == argc)
205 {
206 error (0, 0, _("COUNT parameter required"));
207 argp_help (&argp, stderr, ARGP_HELP_SEE,
208 program_invocation_short_name);
209 exit (EXIT_FAILURE);
210 }
211
212 char *endp;
213 errno = 0;
214 if (((instance = strtol (argv[remaining], &endp, 10)) == LONG_MAX
215 && errno == ERANGE)
216 || instance <= 0
217 || *endp != '\0')
218 error (1, 0, _("invalid COUNT parameter %s"), argv[remaining]);
219
220 ++remaining;
221 }
222
223 if ((dont_replace_existing || allow_truncate_fname)
224 && unlikely (operation != oper_extract))
225 error (1, 0, _("'%c' is only meaningful with the 'x' option"),
226 dont_replace_existing ? 'C' : 'T');
227
228 /* There must at least be one more parameter specifying the archive. */
229 if (remaining == argc)
230 {
231 error (0, 0, _("archive name required"));
232 argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
233 exit (EXIT_FAILURE);
234 }
235
236 const char *arfname = argv[remaining++];
237 argv += remaining;
238 argc -= remaining;
239
240 int status;
241 switch (operation)
242 {
243 case oper_none:
244 error (0, 0, _("command option required"));
245 argp_help (&argp, stderr, ARGP_HELP_STD_ERR,
246 program_invocation_short_name);
247 status = 1;
248 break;
249
250 case oper_list:
251 case oper_print:
252 status = do_oper_extract (operation, arfname, argv, argc, -1);
253 break;
254
255 case oper_extract:
256 status = do_oper_extract (operation, arfname, argv, argc, instance);
257 break;
258
259 case oper_delete:
260 status = do_oper_delete (arfname, argv, argc, instance);
261 break;
262
263 case oper_move:
264 case oper_qappend:
265 case oper_replace:
266 status = do_oper_insert (operation, arfname, argv, argc, member);
267 break;
268
269 default:
270 assert (! "should not happen");
271 status = 1;
272 break;
273 }
274
275 return status;
276 }
277
278
279 /* Handle program arguments. */
280 static error_t
parse_opt(int key,char * arg,struct argp_state * state)281 parse_opt (int key, char *arg __attribute__ ((unused)),
282 struct argp_state *state __attribute__ ((unused)))
283 {
284 switch (key)
285 {
286 case 'd':
287 case 'm':
288 case 'p':
289 case 'q':
290 case 'r':
291 case 't':
292 case 'x':
293 if (operation != oper_none)
294 {
295 error (0, 0, _("More than one operation specified"));
296 argp_help (&argp, stderr, ARGP_HELP_SEE,
297 program_invocation_short_name);
298 exit (EXIT_FAILURE);
299 }
300
301 switch (key)
302 {
303 case 'd':
304 operation = oper_delete;
305 break;
306 case 'm':
307 operation = oper_move;
308 break;
309 case 'p':
310 operation = oper_print;
311 break;
312 case 'q':
313 operation = oper_qappend;
314 break;
315 case 'r':
316 operation = oper_replace;
317 break;
318 case 't':
319 operation = oper_list;
320 break;
321 case 'x':
322 operation = oper_extract;
323 break;
324 }
325 break;
326
327 case 'a':
328 ipos = ipos_after;
329 break;
330
331 case 'b':
332 case 'i':
333 ipos = ipos_before;
334 break;
335
336 case 'c':
337 suppress_create_msg = true;
338 break;
339
340 case 'C':
341 dont_replace_existing = true;
342 break;
343
344 case 'N':
345 instance_specifed = true;
346 break;
347
348 case 'o':
349 preserve_dates = true;
350 break;
351
352 case 'P':
353 full_path = true;
354 break;
355
356 case 's':
357 force_symtab = true;
358 break;
359
360 case 'T':
361 allow_truncate_fname = true;
362 break;
363
364 case 'u':
365 update_newer = true;
366 break;
367
368 case 'v':
369 verbose = true;
370 break;
371
372 default:
373 return ARGP_ERR_UNKNOWN;
374 }
375 return 0;
376 }
377
378
379 static int
open_archive(const char * arfname,int flags,int mode,Elf ** elf,struct stat * st,bool miss_allowed)380 open_archive (const char *arfname, int flags, int mode, Elf **elf,
381 struct stat *st, bool miss_allowed)
382 {
383 int fd = open (arfname, flags, mode);
384 if (fd == -1)
385 {
386 if (miss_allowed)
387 return -1;
388
389 error (EXIT_FAILURE, errno, _("cannot open archive '%s'"),
390 arfname);
391 }
392
393 if (elf != NULL)
394 {
395 Elf_Cmd cmd = flags == O_RDONLY ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP;
396
397 *elf = elf_begin (fd, cmd, NULL);
398 if (*elf == NULL)
399 error (EXIT_FAILURE, 0, _("cannot open archive '%s': %s"),
400 arfname, elf_errmsg (-1));
401
402 if (flags == O_RDONLY && elf_kind (*elf) != ELF_K_AR)
403 error (EXIT_FAILURE, 0, _("%s: not an archive file"), arfname);
404 }
405
406 if (st != NULL && fstat (fd, st) != 0)
407 error (EXIT_FAILURE, errno, _("cannot stat archive '%s'"),
408 arfname);
409
410 return fd;
411 }
412
413
414 static void
not_found(int argc,char * argv[argc],bool found[argc])415 not_found (int argc, char *argv[argc], bool found[argc])
416 {
417 for (int i = 0; i < argc; ++i)
418 if (!found[i])
419 printf (_("no entry %s in archive\n"), argv[i]);
420 }
421
422
423 static int
copy_content(Elf * elf,int newfd,off_t off,size_t n)424 copy_content (Elf *elf, int newfd, off_t off, size_t n)
425 {
426 size_t len;
427 char *rawfile = elf_rawfile (elf, &len);
428
429 assert (off + n <= len);
430
431 /* Tell the kernel we will read all the pages sequentially. */
432 size_t ps = sysconf (_SC_PAGESIZE);
433 if (n > 2 * ps)
434 posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL);
435
436 return write_retry (newfd, rawfile + off, n) != (ssize_t) n;
437 }
438
439 static inline bool
should_truncate_fname(size_t * name_max)440 should_truncate_fname (size_t *name_max)
441 {
442 if (errno == ENAMETOOLONG && allow_truncate_fname)
443 {
444 if (*name_max == 0)
445 {
446 long int len = pathconf (".", _PC_NAME_MAX);
447 if (len > 0)
448 *name_max = len;
449 }
450 return *name_max != 0;
451 }
452 return false;
453 }
454
455 static int
do_oper_extract(int oper,const char * arfname,char ** argv,int argc,long int instance)456 do_oper_extract (int oper, const char *arfname, char **argv, int argc,
457 long int instance)
458 {
459 bool found[argc > 0 ? argc : 1];
460 memset (found, '\0', sizeof (found));
461
462 size_t name_max = 0;
463 off_t index_off = -1;
464 size_t index_size = 0;
465 off_t cur_off = SARMAG;
466
467 int status = 0;
468 Elf *elf;
469 int fd = open_archive (arfname, O_RDONLY, 0, &elf, NULL, false);
470
471 if (hcreate (2 * argc) == 0)
472 error (EXIT_FAILURE, errno, _("cannot create hash table"));
473
474 for (int cnt = 0; cnt < argc; ++cnt)
475 {
476 ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
477 if (hsearch (entry, ENTER) == NULL)
478 error (EXIT_FAILURE, errno,
479 _("cannot insert into hash table"));
480 }
481
482 struct stat st;
483 if (force_symtab)
484 {
485 if (fstat (fd, &st) != 0)
486 {
487 error (0, errno, _("cannot stat '%s'"), arfname);
488 close (fd);
489 return 1;
490 }
491 arlib_init ();
492 }
493
494 Elf_Cmd cmd = ELF_C_READ_MMAP;
495 Elf *subelf;
496 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
497 {
498 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
499
500 if (strcmp (arhdr->ar_name, "/") == 0)
501 {
502 index_off = elf_getaroff (subelf);
503 index_size = arhdr->ar_size;
504 goto next;
505 }
506 if (strcmp (arhdr->ar_name, "//") == 0)
507 goto next;
508
509 if (force_symtab)
510 {
511 arlib_add_symbols (elf, arfname, arhdr->ar_name, cur_off);
512 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
513 + sizeof (struct ar_hdr));
514 }
515
516 bool do_extract = argc <= 0;
517 if (!do_extract)
518 {
519 ENTRY entry;
520 entry.key = arhdr->ar_name;
521 ENTRY *res = hsearch (entry, FIND);
522 if (res != NULL && (instance < 0 || instance-- == 0)
523 && !found[(char **) res->data - argv])
524 found[(char **) res->data - argv] = do_extract = true;
525 }
526
527 if (do_extract)
528 {
529 if (verbose)
530 {
531 if (oper == oper_print)
532 {
533 printf ("\n<%s>\n\n", arhdr->ar_name);
534
535 /* We have to flush now because now we use the descriptor
536 directly. */
537 fflush (stdout);
538 }
539 else if (oper == oper_list)
540 {
541 char datestr[100];
542 struct tm *tp = localtime (&arhdr->ar_date);
543 if (tp == NULL)
544 {
545 time_t time = 0;
546 tp = localtime (&time);
547 }
548
549 strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y", tp);
550
551 printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n",
552 (arhdr->ar_mode & S_IRUSR) ? 'r' : '-',
553 (arhdr->ar_mode & S_IWUSR) ? 'w' : '-',
554 (arhdr->ar_mode & S_IXUSR)
555 ? ((arhdr->ar_mode & S_ISUID) ? 's' : 'x')
556 : ((arhdr->ar_mode & S_ISUID) ? 'S' : '-'),
557 (arhdr->ar_mode & S_IRGRP) ? 'r' : '-',
558 (arhdr->ar_mode & S_IWGRP) ? 'w' : '-',
559 (arhdr->ar_mode & S_IXGRP)
560 ? ((arhdr->ar_mode & S_ISGID) ? 's' : 'x')
561 : ((arhdr->ar_mode & S_ISGID) ? 'S' : '-'),
562 (arhdr->ar_mode & S_IROTH) ? 'r' : '-',
563 (arhdr->ar_mode & S_IWOTH) ? 'w' : '-',
564 (arhdr->ar_mode & S_IXOTH)
565 ? ((arhdr->ar_mode & S_ISVTX) ? 't' : 'x')
566 : ((arhdr->ar_mode & S_ISVTX) ? 'T' : '-'),
567 arhdr->ar_uid,
568 arhdr->ar_gid,
569 (uintmax_t) arhdr->ar_size,
570 datestr,
571 arhdr->ar_name);
572 }
573 else
574 printf ("x - %s\n", arhdr->ar_name);
575 }
576
577 if (oper == oper_list)
578 {
579 if (!verbose)
580 puts (arhdr->ar_name);
581
582 goto next;
583 }
584
585 size_t nleft;
586 char *data = elf_rawfile (subelf, &nleft);
587 if (data == NULL)
588 {
589 error (0, 0, _("cannot read content of %s: %s"),
590 arhdr->ar_name, elf_errmsg (-1));
591 status = 1;
592 goto next;
593 }
594
595 int xfd;
596 char tempfname[] = "XXXXXX";
597 bool use_mkstemp = true;
598
599 if (oper == oper_print)
600 xfd = STDOUT_FILENO;
601 else
602 {
603 xfd = mkstemp (tempfname);
604 if (unlikely (xfd == -1))
605 {
606 /* We cannot create a temporary file. Try to overwrite
607 the file or create it if it does not exist. */
608 int flags = O_WRONLY | O_CREAT;
609 if (dont_replace_existing)
610 flags |= O_EXCL;
611 else
612 flags |= O_TRUNC;
613 xfd = open (arhdr->ar_name, flags, 0600);
614 if (unlikely (xfd == -1))
615 {
616 int printlen = INT_MAX;
617
618 if (should_truncate_fname (&name_max))
619 {
620 /* Try to truncate the name. First find out by how
621 much. */
622 printlen = name_max;
623 char truncfname[name_max + 1];
624 *((char *) mempcpy (truncfname, arhdr->ar_name,
625 name_max)) = '\0';
626
627 xfd = open (truncfname, flags, 0600);
628 }
629
630 if (xfd == -1)
631 {
632 error (0, errno, _("cannot open %.*s"),
633 (int) printlen, arhdr->ar_name);
634 status = 1;
635 goto next;
636 }
637 }
638
639 use_mkstemp = false;
640 }
641 }
642
643 ssize_t n;
644 while ((n = TEMP_FAILURE_RETRY (write (xfd, data, nleft))) != -1)
645 {
646 nleft -= n;
647 if (nleft == 0)
648 break;
649 data += n;
650 }
651
652 if (unlikely (n == -1))
653 {
654 error (0, errno, _("failed to write %s"), arhdr->ar_name);
655 status = 1;
656 unlink (tempfname);
657 close (xfd);
658 goto next;
659 }
660
661 if (oper != oper_print)
662 {
663 /* Fix up the mode. */
664 if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0))
665 {
666 error (0, errno, _("cannot change mode of %s"),
667 arhdr->ar_name);
668 status = 0;
669 }
670
671 if (preserve_dates)
672 {
673 struct timespec tv[2];
674 tv[0].tv_sec = arhdr->ar_date;
675 tv[0].tv_nsec = 0;
676 tv[1].tv_sec = arhdr->ar_date;
677 tv[1].tv_nsec = 0;
678
679 if (unlikely (futimens (xfd, tv) != 0))
680 {
681 error (0, errno,
682 _("cannot change modification time of %s"),
683 arhdr->ar_name);
684 status = 1;
685 }
686 }
687
688 /* If we used a temporary file, move it do the right
689 name now. */
690 if (use_mkstemp)
691 {
692 int r;
693
694 if (dont_replace_existing)
695 {
696 r = link (tempfname, arhdr->ar_name);
697 if (likely (r == 0))
698 unlink (tempfname);
699 }
700 else
701 r = rename (tempfname, arhdr->ar_name);
702
703 if (unlikely (r) != 0)
704 {
705 int printlen = INT_MAX;
706
707 if (should_truncate_fname (&name_max))
708 {
709 /* Try to truncate the name. First find out by how
710 much. */
711 printlen = name_max;
712 char truncfname[name_max + 1];
713 *((char *) mempcpy (truncfname, arhdr->ar_name,
714 name_max)) = '\0';
715
716 if (dont_replace_existing)
717 {
718 r = link (tempfname, truncfname);
719 if (likely (r == 0))
720 unlink (tempfname);
721 }
722 else
723 r = rename (tempfname, truncfname);
724 }
725
726 if (r != 0)
727 {
728 error (0, errno, _("\
729 cannot rename temporary file to %.*s"),
730 printlen, arhdr->ar_name);
731 unlink (tempfname);
732 status = 1;
733 }
734 }
735 }
736
737 close (xfd);
738 }
739 }
740
741 next:
742 cmd = elf_next (subelf);
743 if (elf_end (subelf) != 0)
744 error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
745 }
746
747 hdestroy ();
748
749 if (force_symtab)
750 {
751 arlib_finalize ();
752
753 if (symtab.symsnamelen != 0
754 /* We have to rewrite the file also if it initially had an index
755 but now does not need one anymore. */
756 || (symtab.symsnamelen == 0 && index_size != 0))
757 {
758 char tmpfname[strlen (arfname) + 7];
759 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
760 int newfd = mkstemp (tmpfname);
761 if (unlikely (newfd == -1))
762 {
763 nonew:
764 error (0, errno, _("cannot create new file"));
765 status = 1;
766 }
767 else
768 {
769 /* Create the header. */
770 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
771 {
772 // XXX Use /prof/self/fd/%d ???
773 nonew_unlink:
774 unlink (tmpfname);
775 if (newfd != -1)
776 close (newfd);
777 goto nonew;
778 }
779
780 /* Create the new file. There are three parts as far we are
781 concerned: 1. original context before the index, 2. the
782 new index, 3. everything after the new index. */
783 off_t rest_off;
784 if (index_off != -1)
785 rest_off = (index_off + sizeof (struct ar_hdr)
786 + ((index_size + 1) & ~1ul));
787 else
788 rest_off = SARMAG;
789
790 if (symtab.symsnamelen != 0
791 && ((write_retry (newfd, symtab.symsoff,
792 symtab.symsofflen)
793 != (ssize_t) symtab.symsofflen)
794 || (write_retry (newfd, symtab.symsname,
795 symtab.symsnamelen)
796 != (ssize_t) symtab.symsnamelen)))
797 goto nonew_unlink;
798 /* Even if the original file had content before the
799 symbol table, we write it in the correct order. */
800 if ((index_off != SARMAG
801 && copy_content (elf, newfd, SARMAG, index_off - SARMAG))
802 || copy_content (elf, newfd, rest_off, st.st_size - rest_off))
803 goto nonew_unlink;
804
805 /* Never complain about fchown failing. */
806 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
807 /* Set the mode of the new file to the same values the
808 original file has. */
809 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
810 || close (newfd) != 0)
811 goto nonew_unlink;
812 newfd = -1;
813 if (rename (tmpfname, arfname) != 0)
814 goto nonew_unlink;
815 }
816 }
817 }
818
819 elf_end (elf);
820
821 close (fd);
822
823 not_found (argc, argv, found);
824
825 return status;
826 }
827
828
829 struct armem
830 {
831 off_t off;
832 off_t old_off;
833 size_t size;
834 long int long_name_off;
835 struct armem *next;
836 void *mem;
837 time_t sec;
838 uid_t uid;
839 gid_t gid;
840 mode_t mode;
841 const char *name;
842 Elf *elf;
843 };
844
845
846 static int
write_member(struct armem * memb,off_t * startp,off_t * lenp,Elf * elf,off_t end_off,int newfd)847 write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf,
848 off_t end_off, int newfd)
849 {
850 struct ar_hdr arhdr;
851 /* The ar_name is not actually zero terminated, but we need that for
852 snprintf. Also if the name is too long, then the string starts
853 with '/' plus an index off number (decimal). */
854 char tmpbuf[sizeof (arhdr.ar_name) + 2];
855
856 bool changed_header = memb->long_name_off != -1;
857 if (changed_header)
858 {
859 /* In case of a long file name we assume the archive header
860 changed and we write it here. */
861 memcpy (&arhdr, elf_rawfile (elf, NULL) + *startp, sizeof (arhdr));
862
863 snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
864 (int) sizeof (arhdr.ar_name), memb->long_name_off);
865 changed_header = memcmp (arhdr.ar_name, tmpbuf,
866 sizeof (arhdr.ar_name)) != 0;
867 }
868
869 /* If the files are adjacent in the old file extend the range. */
870 if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off)
871 {
872 /* Extend the current range. */
873 *lenp += (memb->next != NULL
874 ? memb->next->off : end_off) - memb->off;
875 return 0;
876 }
877
878 /* Write out the old range. */
879 if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp))
880 return -1;
881
882 *startp = memb->old_off;
883 *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off;
884
885 if (changed_header)
886 {
887 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
888
889 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
890 != sizeof (arhdr)))
891 return -1;
892
893 *startp += sizeof (struct ar_hdr);
894 assert ((size_t) *lenp >= sizeof (struct ar_hdr));
895 *lenp -= sizeof (struct ar_hdr);
896 }
897
898 return 0;
899 }
900
901 /* Store the name in the long name table if necessary.
902 Record its offset or -1 if we did not need to use the table. */
903 static void
remember_long_name(struct armem * mem,const char * name,size_t namelen)904 remember_long_name (struct armem *mem, const char *name, size_t namelen)
905 {
906 mem->long_name_off = (namelen > MAX_AR_NAME_LEN
907 ? arlib_add_long_name (name, namelen)
908 : -1l);
909 }
910
911 static int
do_oper_delete(const char * arfname,char ** argv,int argc,long int instance)912 do_oper_delete (const char *arfname, char **argv, int argc,
913 long int instance)
914 {
915 bool *found = alloca (sizeof (bool) * argc);
916 memset (found, '\0', sizeof (bool) * argc);
917
918 /* List of the files we keep. */
919 struct armem *to_copy = NULL;
920
921 int status = 0;
922 Elf *elf;
923 struct stat st;
924 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false);
925
926 if (hcreate (2 * argc) == 0)
927 error (EXIT_FAILURE, errno, _("cannot create hash table"));
928
929 for (int cnt = 0; cnt < argc; ++cnt)
930 {
931 ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
932 if (hsearch (entry, ENTER) == NULL)
933 error (EXIT_FAILURE, errno,
934 _("cannot insert into hash table"));
935 }
936
937 arlib_init ();
938
939 off_t cur_off = SARMAG;
940 Elf_Cmd cmd = ELF_C_READ_MMAP;
941 Elf *subelf;
942 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
943 {
944 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
945
946 /* Ignore the symbol table and the long file name table here. */
947 if (strcmp (arhdr->ar_name, "/") == 0
948 || strcmp (arhdr->ar_name, "//") == 0)
949 goto next;
950
951 bool do_delete = argc <= 0;
952 if (!do_delete)
953 {
954 ENTRY entry;
955 entry.key = arhdr->ar_name;
956 ENTRY *res = hsearch (entry, FIND);
957 if (res != NULL && (instance < 0 || instance-- == 0)
958 && !found[(char **) res->data - argv])
959 found[(char **) res->data - argv] = do_delete = true;
960 }
961
962 if (do_delete)
963 {
964 if (verbose)
965 printf ("d - %s\n", arhdr->ar_name);
966 }
967 else
968 {
969 struct armem *newp = alloca (sizeof (struct armem));
970 newp->old_off = elf_getaroff (subelf);
971 newp->off = cur_off;
972
973 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
974 + sizeof (struct ar_hdr));
975
976 if (to_copy == NULL)
977 to_copy = newp->next = newp;
978 else
979 {
980 newp->next = to_copy->next;
981 to_copy = to_copy->next = newp;
982 }
983
984 /* If we recreate the symbol table read the file's symbol
985 table now. */
986 arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
987
988 /* Remember long file names. */
989 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
990 }
991
992 next:
993 cmd = elf_next (subelf);
994 if (elf_end (subelf) != 0)
995 error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
996 }
997
998 arlib_finalize ();
999
1000 hdestroy ();
1001
1002 /* Create a new, temporary file in the same directory as the
1003 original file. */
1004 char tmpfname[strlen (arfname) + 7];
1005 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1006 int newfd = mkstemp (tmpfname);
1007 if (unlikely (newfd == -1))
1008 goto nonew;
1009
1010 /* Create the header. */
1011 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1012 {
1013 // XXX Use /prof/self/fd/%d ???
1014 nonew_unlink:
1015 unlink (tmpfname);
1016 if (newfd != -1)
1017 close (newfd);
1018 nonew:
1019 error (0, errno, _("cannot create new file"));
1020 status = 1;
1021 goto errout;
1022 }
1023
1024 /* If the archive is empty that is all we have to do. */
1025 if (likely (to_copy != NULL))
1026 {
1027 /* Write the symbol table or the long file name table or both. */
1028 if (symtab.symsnamelen != 0
1029 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1030 != (ssize_t) symtab.symsofflen)
1031 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1032 != (ssize_t) symtab.symsnamelen)))
1033 goto nonew_unlink;
1034
1035 if (symtab.longnameslen > sizeof (struct ar_hdr)
1036 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1037 != (ssize_t) symtab.longnameslen))
1038 goto nonew_unlink;
1039
1040 /* NULL-terminate the list of files to copy. */
1041 struct armem *last = to_copy;
1042 to_copy = to_copy->next;
1043 last->next = NULL;
1044
1045 off_t start = -1;
1046 off_t len = -1;
1047
1048 do
1049 if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
1050 goto nonew_unlink;
1051 while ((to_copy = to_copy->next) != NULL);
1052
1053 /* Write the last part. */
1054 if (copy_content (elf, newfd, start, len))
1055 goto nonew_unlink;
1056 }
1057
1058 /* Set the mode of the new file to the same values the original file
1059 has. Never complain about fchown failing. But do it before
1060 setting the mode (which might be reset/ignored if the owner is
1061 wrong. */
1062 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1063 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1064 || close (newfd) != 0)
1065 goto nonew_unlink;
1066 newfd = -1;
1067 if (rename (tmpfname, arfname) != 0)
1068 goto nonew_unlink;
1069
1070 errout:
1071 elf_end (elf);
1072
1073 arlib_fini ();
1074
1075 close (fd);
1076
1077 not_found (argc, argv, found);
1078
1079 return status;
1080 }
1081
1082
1083 /* Prints the given value in the given buffer without a trailing zero char.
1084 Returns false if the given value doesn't fit in the given buffer. */
1085 static bool
no0print(bool ofmt,char * buf,int bufsize,long int val)1086 no0print (bool ofmt, char *buf, int bufsize, long int val)
1087 {
1088 char tmpbuf[bufsize + 1];
1089 int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld",
1090 bufsize, val);
1091 if (ret >= (int) sizeof (tmpbuf))
1092 return false;
1093 memcpy (buf, tmpbuf, bufsize);
1094 return true;
1095 }
1096
1097
1098 static int
do_oper_insert(int oper,const char * arfname,char ** argv,int argc,const char * member)1099 do_oper_insert (int oper, const char *arfname, char **argv, int argc,
1100 const char *member)
1101 {
1102 int status = 0;
1103 Elf *elf = NULL;
1104 struct stat st;
1105 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
1106
1107 /* List of the files we keep. */
1108 struct armem *all = NULL;
1109 struct armem *after_memberelem = NULL;
1110 struct armem **found = alloca (sizeof (*found) * argc);
1111 memset (found, '\0', sizeof (*found) * argc);
1112
1113 arlib_init ();
1114
1115 /* Initialize early for no_old case. */
1116 off_t cur_off = SARMAG;
1117
1118 if (fd == -1)
1119 {
1120 if (!suppress_create_msg)
1121 fprintf (stderr, "%s: creating %s\n",
1122 program_invocation_short_name, arfname);
1123
1124 goto no_old;
1125 }
1126
1127 /* Store the names of all files from the command line in a hash
1128 table so that we can match it. Note that when no file name is
1129 given we are basically doing nothing except recreating the
1130 index. */
1131 if (oper != oper_qappend)
1132 {
1133 if (hcreate (2 * argc) == 0)
1134 error (EXIT_FAILURE, errno, _("cannot create hash table"));
1135
1136 for (int cnt = 0; cnt < argc; ++cnt)
1137 {
1138 ENTRY entry;
1139 entry.key = full_path ? argv[cnt] : basename (argv[cnt]);
1140 entry.data = &argv[cnt];
1141 if (hsearch (entry, ENTER) == NULL)
1142 error (EXIT_FAILURE, errno,
1143 _("cannot insert into hash table"));
1144 }
1145 }
1146
1147 /* While iterating over the current content of the archive we must
1148 determine a number of things: which archive members to keep,
1149 which are replaced, and where to insert the new members. */
1150 Elf_Cmd cmd = ELF_C_READ_MMAP;
1151 Elf *subelf;
1152 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
1153 {
1154 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
1155
1156 /* Ignore the symbol table and the long file name table here. */
1157 if (strcmp (arhdr->ar_name, "/") == 0
1158 || strcmp (arhdr->ar_name, "//") == 0)
1159 goto next;
1160
1161 struct armem *newp = alloca (sizeof (struct armem));
1162 newp->old_off = elf_getaroff (subelf);
1163 newp->size = arhdr->ar_size;
1164 newp->sec = arhdr->ar_date;
1165 newp->mem = NULL;
1166
1167 /* Remember long file names. */
1168 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
1169
1170 /* Check whether this is a file we are looking for. */
1171 if (oper != oper_qappend)
1172 {
1173 /* Check whether this is the member used as the insert point. */
1174 if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
1175 {
1176 /* Note that all == NULL means insert at the beginning. */
1177 if (ipos == ipos_before)
1178 after_memberelem = all;
1179 else
1180 after_memberelem = newp;
1181 member = NULL;
1182 }
1183
1184 ENTRY entry;
1185 entry.key = arhdr->ar_name;
1186 ENTRY *res = hsearch (entry, FIND);
1187 if (res != NULL && found[(char **) res->data - argv] == NULL)
1188 {
1189 found[(char **) res->data - argv] = newp;
1190
1191 /* If we insert before or after a certain element move
1192 all files to a special list. */
1193 if (unlikely (ipos != ipos_none || oper == oper_move))
1194 {
1195 if (after_memberelem == newp)
1196 /* Since we remove this element even though we should
1197 insert everything after it, we in fact insert
1198 everything after the previous element. */
1199 after_memberelem = all;
1200
1201 goto next;
1202 }
1203 }
1204 }
1205
1206 if (all == NULL)
1207 all = newp->next = newp;
1208 else
1209 {
1210 newp->next = all->next;
1211 all = all->next = newp;
1212 }
1213
1214 next:
1215 cmd = elf_next (subelf);
1216 if (elf_end (subelf) != 0)
1217 error (EXIT_FAILURE, 0, "%s: %s", arfname, elf_errmsg (-1));
1218 }
1219
1220 if (oper != oper_qappend)
1221 hdestroy ();
1222
1223 no_old:
1224 if (member != NULL)
1225 error (EXIT_FAILURE, 0, _("position member %s not found"),
1226 member);
1227
1228 if (oper == oper_move)
1229 {
1230 /* Make sure all requested elements are found in the archive. */
1231 for (int cnt = 0; cnt < argc; ++cnt)
1232 {
1233 if (found[cnt] == NULL)
1234 {
1235 fprintf (stderr, _("%s: no entry %s in archive!\n"),
1236 program_invocation_short_name, argv[cnt]);
1237 status = 1;
1238 }
1239
1240 if (verbose)
1241 printf ("m - %s\n", argv[cnt]);
1242 }
1243 }
1244 else
1245 {
1246 /* Open all the new files, get their sizes and add all symbols. */
1247 for (int cnt = 0; cnt < argc; ++cnt)
1248 {
1249 const char *bname = basename (argv[cnt]);
1250 size_t bnamelen = strlen (bname);
1251 if (found[cnt] == NULL)
1252 {
1253 found[cnt] = alloca (sizeof (struct armem));
1254 found[cnt]->old_off = -1;
1255
1256 remember_long_name (found[cnt], bname, bnamelen);
1257 }
1258
1259 struct stat newst;
1260 Elf *newelf;
1261 int newfd = open (argv[cnt], O_RDONLY);
1262 if (newfd == -1)
1263 {
1264 error (0, errno, _("cannot open %s"), argv[cnt]);
1265 status = 1;
1266 }
1267 else if (fstat (newfd, &newst) == -1)
1268 {
1269 error (0, errno, _("cannot stat %s"), argv[cnt]);
1270 close (newfd);
1271 status = 1;
1272 }
1273 else if (!S_ISREG (newst.st_mode))
1274 {
1275 error (0, errno, _("%s is no regular file"), argv[cnt]);
1276 close (newfd);
1277 status = 1;
1278 }
1279 else if (update_newer
1280 && found[cnt]->old_off != -1l
1281 && found[cnt]->sec > st.st_mtime)
1282 /* Do nothing, the file in the archive is younger. */
1283 close (newfd);
1284 else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
1285 == NULL)
1286 {
1287 fprintf (stderr,
1288 _("cannot get ELF descriptor for %s: %s\n"),
1289 argv[cnt], elf_errmsg (-1));
1290 status = 1;
1291 }
1292 else
1293 {
1294 if (verbose)
1295 printf ("%c - %s\n",
1296 found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
1297
1298 found[cnt]->elf = newelf;
1299 found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime;
1300 found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid;
1301 found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid;
1302 found[cnt]->mode = newst.st_mode;
1303 found[cnt]->name = bname;
1304
1305 found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
1306 if (found[cnt]->mem == NULL
1307 || elf_cntl (newelf, ELF_C_FDDONE) != 0)
1308 error (EXIT_FAILURE, 0, _("cannot read %s: %s"),
1309 argv[cnt], elf_errmsg (-1));
1310
1311 close (newfd);
1312
1313 if (found[cnt]->old_off != -1l)
1314 /* Remember long file names. */
1315 remember_long_name (found[cnt], bname, bnamelen);
1316 }
1317 }
1318 }
1319
1320 if (status != 0)
1321 {
1322 elf_end (elf);
1323
1324 arlib_fini ();
1325
1326 close (fd);
1327
1328 return status;
1329 }
1330
1331 /* If we have no entry point so far add at the end. AFTER_MEMBERELEM
1332 being NULL when adding before an entry means add at the beginning. */
1333 if (ipos != ipos_before && after_memberelem == NULL)
1334 after_memberelem = all;
1335
1336 /* Convert the circular list into a normal list first. */
1337 if (all != NULL)
1338 {
1339 struct armem *tmp = all;
1340 all = all->next;
1341 tmp->next = NULL;
1342 }
1343
1344 struct armem *last_added = after_memberelem;
1345 for (int cnt = 0; cnt < argc; ++cnt)
1346 if (oper != oper_replace || found[cnt]->old_off == -1)
1347 {
1348 if (last_added == NULL)
1349 {
1350 found[cnt]->next = all;
1351 last_added = all = found[cnt];
1352 }
1353 else
1354 {
1355 found[cnt]->next = last_added->next;
1356 last_added = last_added->next = found[cnt];
1357 }
1358 }
1359
1360 /* Finally compute the offset and add the symbols for the files
1361 after the insert point. */
1362 if (likely (all != NULL))
1363 for (struct armem *memp = all; memp != NULL; memp = memp->next)
1364 {
1365 memp->off = cur_off;
1366
1367 if (memp->mem == NULL)
1368 {
1369 Elf_Arhdr *arhdr;
1370 /* Fake initializing arhdr and subelf to keep gcc calm. */
1371 asm ("" : "=m" (arhdr), "=m" (subelf));
1372 if (elf_rand (elf, memp->old_off) == 0
1373 || (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL
1374 || (arhdr = elf_getarhdr (subelf)) == NULL)
1375 /* This should never happen since we already looked at the
1376 archive content. But who knows... */
1377 error (EXIT_FAILURE, 0, "%s: %s", arfname, elf_errmsg (-1));
1378
1379 arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
1380
1381 elf_end (subelf);
1382 }
1383 else
1384 arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
1385
1386 cur_off += (((memp->size + 1) & ~((off_t) 1))
1387 + sizeof (struct ar_hdr));
1388 }
1389
1390 /* Now we have all the information for the symbol table and long
1391 file name table. Construct the final layout. */
1392 arlib_finalize ();
1393
1394 /* Create a new, temporary file in the same directory as the
1395 original file. */
1396 char tmpfname[strlen (arfname) + 7];
1397 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1398 int newfd;
1399 if (fd != -1)
1400 newfd = mkstemp (tmpfname);
1401 else
1402 {
1403 newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE);
1404 if (newfd == -1 && errno == EEXIST)
1405 /* Bah, first the file did not exist, now it does. Restart. */
1406 return do_oper_insert (oper, arfname, argv, argc, member);
1407 }
1408 if (unlikely (newfd == -1))
1409 goto nonew;
1410
1411 /* Create the header. */
1412 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1413 {
1414 nonew_unlink:
1415 if (fd != -1)
1416 {
1417 // XXX Use /prof/self/fd/%d ???
1418 unlink (tmpfname);
1419 if (newfd != -1)
1420 close (newfd);
1421 }
1422 nonew:
1423 error (0, errno, _("cannot create new file"));
1424 status = 1;
1425 goto errout;
1426 }
1427
1428 /* If the new archive is not empty we actually have something to do. */
1429 if (likely (all != NULL))
1430 {
1431 /* Write the symbol table or the long file name table or both. */
1432 if (symtab.symsnamelen != 0
1433 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1434 != (ssize_t) symtab.symsofflen)
1435 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1436 != (ssize_t) symtab.symsnamelen)))
1437 goto nonew_unlink;
1438
1439 if (symtab.longnameslen > sizeof (struct ar_hdr)
1440 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1441 != (ssize_t) symtab.longnameslen))
1442 goto nonew_unlink;
1443
1444 off_t start = -1;
1445 off_t len = -1;
1446
1447 while (all != NULL)
1448 {
1449 if (all->mem != NULL)
1450 {
1451 /* This is a new file. If there is anything from the
1452 archive left to be written do it now. */
1453 if (start != -1 && copy_content (elf, newfd, start, len))
1454 goto nonew_unlink;
1455
1456 start = -1;
1457 len = -1;
1458
1459 /* Create the header. */
1460 struct ar_hdr arhdr;
1461 /* The ar_name is not actually zero terminated, but we
1462 need that for snprintf. Also if the name is too
1463 long, then the string starts with '/' plus an index
1464 off number (decimal). */
1465 char tmpbuf[sizeof (arhdr.ar_name) + 2];
1466 if (all->long_name_off == -1)
1467 {
1468 size_t namelen = strlen (all->name);
1469 char *p = mempcpy (arhdr.ar_name, all->name, namelen);
1470 *p++ = '/';
1471 memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
1472 }
1473 else
1474 {
1475 snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
1476 (int) sizeof (arhdr.ar_name), all->long_name_off);
1477 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
1478 }
1479
1480 if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
1481 all->sec))
1482 {
1483 error (0, errno, _("cannot represent ar_date"));
1484 goto nonew_unlink;
1485 }
1486 if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid),
1487 all->uid))
1488 {
1489 error (0, errno, _("cannot represent ar_uid"));
1490 goto nonew_unlink;
1491 }
1492 if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid),
1493 all->gid))
1494 {
1495 error (0, errno, _("cannot represent ar_gid"));
1496 goto nonew_unlink;
1497 }
1498 if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode),
1499 all->mode))
1500 {
1501 error (0, errno, _("cannot represent ar_mode"));
1502 goto nonew_unlink;
1503 }
1504 if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
1505 all->size))
1506 {
1507 error (0, errno, _("cannot represent ar_size"));
1508 goto nonew_unlink;
1509 }
1510 memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
1511
1512 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
1513 != sizeof (arhdr)))
1514 goto nonew_unlink;
1515
1516 /* Now the file itself. */
1517 if (unlikely (write_retry (newfd, all->mem, all->size)
1518 != (off_t) all->size))
1519 goto nonew_unlink;
1520
1521 /* Pad the file if its size is odd. */
1522 if ((all->size & 1) != 0)
1523 if (unlikely (write_retry (newfd, "\n", 1) != 1))
1524 goto nonew_unlink;
1525 }
1526 else
1527 {
1528 /* This is a member from the archive. */
1529 if (write_member (all, &start, &len, elf, cur_off, newfd)
1530 != 0)
1531 goto nonew_unlink;
1532 }
1533
1534 all = all->next;
1535 }
1536
1537 /* Write the last part. */
1538 if (start != -1 && copy_content (elf, newfd, start, len))
1539 goto nonew_unlink;
1540 }
1541
1542 /* Set the mode of the new file to the same values the original file
1543 has. */
1544 if (fd != -1)
1545 {
1546 /* Never complain about fchown failing. But do it before
1547 setting the modes, or they might be reset/ignored if the
1548 owner is wrong. */
1549 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1550 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1551 || close (newfd) != 0)
1552 goto nonew_unlink;
1553 newfd = -1;
1554 if (rename (tmpfname, arfname) != 0)
1555 goto nonew_unlink;
1556 }
1557
1558 errout:
1559 for (int cnt = 0; cnt < argc; ++cnt)
1560 elf_end (found[cnt]->elf);
1561
1562 elf_end (elf);
1563
1564 arlib_fini ();
1565
1566 if (fd != -1)
1567 close (fd);
1568
1569 return status;
1570 }
1571
1572
1573 #include "debugpred.h"
1574