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 <limits.h>
28 #include <locale.h>
29 #include <search.h>
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <stdio_ext.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40
41 #include <system.h>
42 #include <printversion.h>
43
44 #include "arlib.h"
45
46
47 /* Name and version of program. */
48 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
49
50 /* Prototypes for local functions. */
51 static int do_oper_extract (int oper, const char *arfname, char **argv,
52 int argc, long int instance);
53 static int do_oper_delete (const char *arfname, char **argv, int argc,
54 long int instance);
55 static int do_oper_insert (int oper, const char *arfname, char **argv,
56 int argc, const char *member);
57
58
59 /* Bug report address. */
60 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
61
62
63 /* Definitions of arguments for argp functions. */
64 static const struct argp_option options[] =
65 {
66 { NULL, 0, NULL, 0, N_("Commands:"), 1 },
67 { NULL, 'd', NULL, 0, N_("Delete files from archive."), 0 },
68 { NULL, 'm', NULL, 0, N_("Move files in archive."), 0 },
69 { NULL, 'p', NULL, 0, N_("Print files in archive."), 0 },
70 { NULL, 'q', NULL, 0, N_("Quick append files to archive."), 0 },
71 { NULL, 'r', NULL, 0,
72 N_("Replace existing or insert new file into archive."), 0 },
73 { NULL, 't', NULL, 0, N_("Display content of archive."), 0 },
74 { NULL, 'x', NULL, 0, N_("Extract files from archive."), 0 },
75
76 { NULL, 0, NULL, 0, N_("Command Modifiers:"), 2 },
77 { NULL, 'o', NULL, 0, N_("Preserve original dates."), 0 },
78 { NULL, 'N', NULL, 0, N_("Use instance [COUNT] of name."), 0 },
79 { NULL, 'C', NULL, 0,
80 N_("Do not replace existing files with extracted files."), 0 },
81 { NULL, 'T', NULL, 0, N_("Allow filename to be truncated if necessary."),
82 0 },
83 { NULL, 'v', NULL, 0, N_("Provide verbose output."), 0 },
84 { NULL, 's', NULL, 0, N_("Force regeneration of symbol table."), 0 },
85 { NULL, 'a', NULL, 0, N_("Insert file after [MEMBER]."), 0 },
86 { NULL, 'b', NULL, 0, N_("Insert file before [MEMBER]."), 0 },
87 { NULL, 'i', NULL, 0, N_("Same as -b."), 0 },
88 { NULL, 'c', NULL, 0, N_("Suppress message when library has to be created."),
89 0 },
90 { NULL, 'P', NULL, 0, N_("Use full path for file matching."), 0 },
91 { NULL, 'u', NULL, 0, N_("Update only older files in archive."), 0 },
92
93 { NULL, 0, NULL, 0, NULL, 0 }
94 };
95
96 /* Short description of program. */
97 static const char doc[] = N_("Create, modify, and extract from archives.");
98
99 /* Strings for arguments in help texts. */
100 static const char args_doc[] = N_("[MEMBER] [COUNT] ARCHIVE [FILE...]");
101
102 /* Prototype for option handler. */
103 static error_t parse_opt (int key, char *arg, struct argp_state *state);
104
105 /* Data structure to communicate with argp functions. */
106 static struct argp argp =
107 {
108 options, parse_opt, args_doc, doc, arlib_argp_children, NULL, NULL
109 };
110
111
112 /* What operation to perform. */
113 static enum
114 {
115 oper_none,
116 oper_delete,
117 oper_move,
118 oper_print,
119 oper_qappend,
120 oper_replace,
121 oper_list,
122 oper_extract
123 } operation;
124
125 /* Modifiers. */
126 static bool verbose;
127 static bool preserve_dates;
128 static bool instance_specifed;
129 static bool dont_replace_existing;
130 static bool allow_truncate_fname;
131 static bool force_symtab;
132 static bool suppress_create_msg;
133 static bool full_path;
134 static bool update_newer;
135 static enum { ipos_none, ipos_before, ipos_after } ipos;
136
137
138 int
main(int argc,char * argv[])139 main (int argc, char *argv[])
140 {
141 /* We use no threads here which can interfere with handling a stream. */
142 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
143 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
144 (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
145
146 /* Set locale. */
147 (void) setlocale (LC_ALL, "");
148
149 /* Make sure the message catalog can be found. */
150 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
151
152 /* Initialize the message catalog. */
153 (void) textdomain (PACKAGE_TARNAME);
154
155 /* For historical reasons the options in the first parameter need
156 not be preceded by a dash. Add it now if necessary. */
157 if (argc > 1 && argv[1][0] != '-')
158 {
159 size_t len = strlen (argv[1]) + 1;
160 char *newp = alloca (len + 1);
161 newp[0] = '-';
162 memcpy (&newp[1], argv[1], len);
163 argv[1] = newp;
164 }
165
166 /* Parse and process arguments. */
167 int remaining;
168 (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL);
169
170 /* Tell the library which version we are expecting. */
171 (void) elf_version (EV_CURRENT);
172
173 /* Handle the [MEMBER] parameter. */
174 const char *member = NULL;
175 if (ipos != ipos_none)
176 {
177 /* Only valid for certain operations. */
178 if (operation != oper_move && operation != oper_replace)
179 error (1, 0, _("\
180 'a', 'b', and 'i' are only allowed with the 'm' and 'r' options"));
181
182 if (remaining == argc)
183 {
184 error (0, 0, _("\
185 MEMBER parameter required for 'a', 'b', and 'i' modifiers"));
186 argp_help (&argp, stderr, ARGP_HELP_USAGE | ARGP_HELP_SEE,
187 program_invocation_short_name);
188 exit (EXIT_FAILURE);
189 }
190
191 member = argv[remaining++];
192 }
193
194 /* Handle the [COUNT] parameter. */
195 long int instance = -1;
196 if (instance_specifed)
197 {
198 /* Only valid for certain operations. */
199 if (operation != oper_extract && operation != oper_delete)
200 error (1, 0, _("\
201 'N' is only meaningful with the 'x' and 'd' options"));
202
203 if (remaining == argc)
204 {
205 error (0, 0, _("COUNT parameter required"));
206 argp_help (&argp, stderr, ARGP_HELP_SEE,
207 program_invocation_short_name);
208 exit (EXIT_FAILURE);
209 }
210
211 char *endp;
212 errno = 0;
213 if (((instance = strtol (argv[remaining], &endp, 10)) == LONG_MAX
214 && errno == ERANGE)
215 || instance <= 0
216 || *endp != '\0')
217 error (1, 0, _("invalid COUNT parameter %s"), argv[remaining]);
218
219 ++remaining;
220 }
221
222 if ((dont_replace_existing || allow_truncate_fname)
223 && unlikely (operation != oper_extract))
224 error (1, 0, _("'%c' is only meaningful with the 'x' option"),
225 dont_replace_existing ? 'C' : 'T');
226
227 /* There must at least be one more parameter specifying the archive. */
228 if (remaining == argc)
229 {
230 error (0, 0, _("archive name required"));
231 argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
232 exit (EXIT_FAILURE);
233 }
234
235 const char *arfname = argv[remaining++];
236 argv += remaining;
237 argc -= remaining;
238
239 int status;
240 switch (operation)
241 {
242 case oper_none:
243 error (0, 0, _("command option required"));
244 argp_help (&argp, stderr, ARGP_HELP_STD_ERR,
245 program_invocation_short_name);
246 status = 1;
247 break;
248
249 case oper_list:
250 case oper_print:
251 status = do_oper_extract (operation, arfname, argv, argc, -1);
252 break;
253
254 case oper_extract:
255 status = do_oper_extract (operation, arfname, argv, argc, instance);
256 break;
257
258 case oper_delete:
259 status = do_oper_delete (arfname, argv, argc, instance);
260 break;
261
262 case oper_move:
263 case oper_qappend:
264 case oper_replace:
265 status = do_oper_insert (operation, arfname, argv, argc, member);
266 break;
267
268 default:
269 assert (! "should not happen");
270 status = 1;
271 break;
272 }
273
274 return status;
275 }
276
277
278 /* Handle program arguments. */
279 static error_t
parse_opt(int key,char * arg,struct argp_state * state)280 parse_opt (int key, char *arg __attribute__ ((unused)),
281 struct argp_state *state __attribute__ ((unused)))
282 {
283 switch (key)
284 {
285 case 'd':
286 case 'm':
287 case 'p':
288 case 'q':
289 case 'r':
290 case 't':
291 case 'x':
292 if (operation != oper_none)
293 {
294 error (0, 0, _("More than one operation specified"));
295 argp_help (&argp, stderr, ARGP_HELP_SEE,
296 program_invocation_short_name);
297 exit (EXIT_FAILURE);
298 }
299
300 switch (key)
301 {
302 case 'd':
303 operation = oper_delete;
304 break;
305 case 'm':
306 operation = oper_move;
307 break;
308 case 'p':
309 operation = oper_print;
310 break;
311 case 'q':
312 operation = oper_qappend;
313 break;
314 case 'r':
315 operation = oper_replace;
316 break;
317 case 't':
318 operation = oper_list;
319 break;
320 case 'x':
321 operation = oper_extract;
322 break;
323 }
324 break;
325
326 case 'a':
327 ipos = ipos_after;
328 break;
329
330 case 'b':
331 case 'i':
332 ipos = ipos_before;
333 break;
334
335 case 'c':
336 suppress_create_msg = true;
337 break;
338
339 case 'C':
340 dont_replace_existing = true;
341 break;
342
343 case 'N':
344 instance_specifed = true;
345 break;
346
347 case 'o':
348 preserve_dates = true;
349 break;
350
351 case 'P':
352 full_path = true;
353 break;
354
355 case 's':
356 force_symtab = true;
357 break;
358
359 case 'T':
360 allow_truncate_fname = true;
361 break;
362
363 case 'u':
364 update_newer = true;
365 break;
366
367 case 'v':
368 verbose = true;
369 break;
370
371 default:
372 return ARGP_ERR_UNKNOWN;
373 }
374 return 0;
375 }
376
377
378 static int
open_archive(const char * arfname,int flags,int mode,Elf ** elf,struct stat * st,bool miss_allowed)379 open_archive (const char *arfname, int flags, int mode, Elf **elf,
380 struct stat *st, bool miss_allowed)
381 {
382 int fd = open (arfname, flags, mode);
383 if (fd == -1)
384 {
385 if (miss_allowed)
386 return -1;
387
388 error_exit (errno, _("cannot open archive '%s'"),
389 arfname);
390 }
391
392 if (elf != NULL)
393 {
394 Elf_Cmd cmd = flags == O_RDONLY ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP;
395
396 *elf = elf_begin (fd, cmd, NULL);
397 if (*elf == NULL)
398 error_exit (0, _("cannot open archive '%s': %s"),
399 arfname, elf_errmsg (-1));
400
401 if (flags == O_RDONLY && elf_kind (*elf) != ELF_K_AR)
402 error_exit (0, _("%s: not an archive file"), arfname);
403 }
404
405 if (st != NULL && fstat (fd, st) != 0)
406 error_exit (errno, _("cannot stat archive '%s'"),
407 arfname);
408
409 return fd;
410 }
411
412
413 static void
not_found(int argc,char * argv[argc],bool found[argc])414 not_found (int argc, char *argv[argc], bool found[argc])
415 {
416 for (int i = 0; i < argc; ++i)
417 if (!found[i])
418 printf (_("no entry %s in archive\n"), argv[i]);
419 }
420
421
422 static int
copy_content(Elf * elf,int newfd,off_t off,size_t n)423 copy_content (Elf *elf, int newfd, off_t off, size_t n)
424 {
425 size_t len;
426 char *rawfile = elf_rawfile (elf, &len);
427
428 assert (off + n <= len);
429
430 /* Tell the kernel we will read all the pages sequentially. */
431 size_t ps = sysconf (_SC_PAGESIZE);
432 if (n > 2 * ps)
433 posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL);
434
435 return write_retry (newfd, rawfile + off, n) != (ssize_t) n;
436 }
437
438 static inline bool
should_truncate_fname(size_t * name_max)439 should_truncate_fname (size_t *name_max)
440 {
441 if (errno == ENAMETOOLONG && allow_truncate_fname)
442 {
443 if (*name_max == 0)
444 {
445 long int len = pathconf (".", _PC_NAME_MAX);
446 if (len > 0)
447 *name_max = len;
448 }
449 return *name_max != 0;
450 }
451 return false;
452 }
453
454 static int
do_oper_extract(int oper,const char * arfname,char ** argv,int argc,long int instance)455 do_oper_extract (int oper, const char *arfname, char **argv, int argc,
456 long int instance)
457 {
458 bool found[argc > 0 ? argc : 1];
459 memset (found, '\0', sizeof (found));
460
461 size_t name_max = 0;
462 off_t index_off = -1;
463 size_t index_size = 0;
464 off_t cur_off = SARMAG;
465
466 int status = 0;
467 Elf *elf;
468 int fd = open_archive (arfname, O_RDONLY, 0, &elf, NULL, false);
469
470 if (hcreate (2 * argc) == 0)
471 error_exit (errno, _("cannot create hash table"));
472
473 for (int cnt = 0; cnt < argc; ++cnt)
474 {
475 ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
476 if (hsearch (entry, ENTER) == NULL)
477 error_exit (errno, _("cannot insert into hash table"));
478 }
479
480 struct stat st;
481 if (force_symtab)
482 {
483 if (fstat (fd, &st) != 0)
484 {
485 error (0, errno, _("cannot stat '%s'"), arfname);
486 close (fd);
487 return 1;
488 }
489 arlib_init ();
490 }
491
492 Elf_Cmd cmd = ELF_C_READ_MMAP;
493 Elf *subelf;
494 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
495 {
496 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
497 if (arhdr == NULL)
498 goto next;
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 (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 (errno, _("cannot insert into hash table"));
934 }
935
936 arlib_init ();
937
938 off_t cur_off = SARMAG;
939 Elf_Cmd cmd = ELF_C_READ_MMAP;
940 Elf *subelf;
941 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
942 {
943 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
944 if (arhdr == NULL)
945 goto next;
946
947 /* Ignore the symbol table and the long file name table here. */
948 if (strcmp (arhdr->ar_name, "/") == 0
949 || strcmp (arhdr->ar_name, "//") == 0)
950 goto next;
951
952 bool do_delete = argc <= 0;
953 if (!do_delete)
954 {
955 ENTRY entry;
956 entry.key = arhdr->ar_name;
957 ENTRY *res = hsearch (entry, FIND);
958 if (res != NULL && (instance < 0 || --instance == 0)
959 && !found[(char **) res->data - argv])
960 found[(char **) res->data - argv] = do_delete = true;
961 }
962
963 if (do_delete)
964 {
965 if (verbose)
966 printf ("d - %s\n", arhdr->ar_name);
967 }
968 else
969 {
970 struct armem *newp = alloca (sizeof (struct armem));
971 newp->old_off = elf_getaroff (subelf);
972 newp->off = cur_off;
973
974 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
975 + sizeof (struct ar_hdr));
976
977 if (to_copy == NULL)
978 to_copy = newp->next = newp;
979 else
980 {
981 newp->next = to_copy->next;
982 to_copy = to_copy->next = newp;
983 }
984
985 /* If we recreate the symbol table read the file's symbol
986 table now. */
987 arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
988
989 /* Remember long file names. */
990 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
991 }
992
993 next:
994 cmd = elf_next (subelf);
995 if (elf_end (subelf) != 0)
996 error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
997 }
998
999 arlib_finalize ();
1000
1001 hdestroy ();
1002
1003 /* Create a new, temporary file in the same directory as the
1004 original file. */
1005 char tmpfname[strlen (arfname) + 7];
1006 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1007 int newfd = mkstemp (tmpfname);
1008 if (unlikely (newfd == -1))
1009 goto nonew;
1010
1011 /* Create the header. */
1012 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1013 {
1014 // XXX Use /prof/self/fd/%d ???
1015 nonew_unlink:
1016 unlink (tmpfname);
1017 if (newfd != -1)
1018 close (newfd);
1019 nonew:
1020 error (0, errno, _("cannot create new file"));
1021 status = 1;
1022 goto errout;
1023 }
1024
1025 /* If the archive is empty that is all we have to do. */
1026 if (likely (to_copy != NULL))
1027 {
1028 /* Write the symbol table or the long file name table or both. */
1029 if (symtab.symsnamelen != 0
1030 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1031 != (ssize_t) symtab.symsofflen)
1032 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1033 != (ssize_t) symtab.symsnamelen)))
1034 goto nonew_unlink;
1035
1036 if (symtab.longnameslen > sizeof (struct ar_hdr)
1037 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1038 != (ssize_t) symtab.longnameslen))
1039 goto nonew_unlink;
1040
1041 /* NULL-terminate the list of files to copy. */
1042 struct armem *last = to_copy;
1043 to_copy = to_copy->next;
1044 last->next = NULL;
1045
1046 off_t start = -1;
1047 off_t len = -1;
1048
1049 do
1050 if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
1051 goto nonew_unlink;
1052 while ((to_copy = to_copy->next) != NULL);
1053
1054 /* Write the last part. */
1055 if (copy_content (elf, newfd, start, len))
1056 goto nonew_unlink;
1057 }
1058
1059 /* Set the mode of the new file to the same values the original file
1060 has. Never complain about fchown failing. But do it before
1061 setting the mode (which might be reset/ignored if the owner is
1062 wrong. */
1063 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1064 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1065 || close (newfd) != 0)
1066 goto nonew_unlink;
1067 newfd = -1;
1068 if (rename (tmpfname, arfname) != 0)
1069 goto nonew_unlink;
1070
1071 errout:
1072 elf_end (elf);
1073
1074 arlib_fini ();
1075
1076 close (fd);
1077
1078 not_found (argc, argv, found);
1079
1080 return status;
1081 }
1082
1083
1084 /* Prints the given value in the given buffer without a trailing zero char.
1085 Returns false if the given value doesn't fit in the given buffer. */
1086 static bool
no0print(bool ofmt,char * buf,int bufsize,long int val)1087 no0print (bool ofmt, char *buf, int bufsize, long int val)
1088 {
1089 char tmpbuf[bufsize + 1];
1090 int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld",
1091 bufsize, val);
1092 if (ret >= (int) sizeof (tmpbuf))
1093 return false;
1094 memcpy (buf, tmpbuf, bufsize);
1095 return true;
1096 }
1097
1098
1099 static int
do_oper_insert(int oper,const char * arfname,char ** argv,int argc,const char * member)1100 do_oper_insert (int oper, const char *arfname, char **argv, int argc,
1101 const char *member)
1102 {
1103 int status = 0;
1104 Elf *elf = NULL;
1105 struct stat st;
1106 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
1107
1108 /* List of the files we keep. */
1109 struct armem *all = NULL;
1110 struct armem *after_memberelem = NULL;
1111 struct armem **found = alloca (sizeof (*found) * argc);
1112 memset (found, '\0', sizeof (*found) * argc);
1113
1114 arlib_init ();
1115
1116 /* Initialize early for no_old case. */
1117 off_t cur_off = SARMAG;
1118
1119 if (fd == -1)
1120 {
1121 if (!suppress_create_msg)
1122 fprintf (stderr, "%s: creating %s\n",
1123 program_invocation_short_name, arfname);
1124
1125 goto no_old;
1126 }
1127
1128 /* Store the names of all files from the command line in a hash
1129 table so that we can match it. Note that when no file name is
1130 given we are basically doing nothing except recreating the
1131 index. */
1132 if (oper != oper_qappend)
1133 {
1134 if (hcreate (2 * argc) == 0)
1135 error_exit (errno, _("cannot create hash table"));
1136
1137 for (int cnt = 0; cnt < argc; ++cnt)
1138 {
1139 ENTRY entry;
1140 entry.key = full_path ? argv[cnt] : basename (argv[cnt]);
1141 entry.data = &argv[cnt];
1142 if (hsearch (entry, ENTER) == NULL)
1143 error_exit (errno, _("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 if (arhdr == NULL)
1156 goto next;
1157
1158 /* Ignore the symbol table and the long file name table here. */
1159 if (strcmp (arhdr->ar_name, "/") == 0
1160 || strcmp (arhdr->ar_name, "//") == 0)
1161 goto next;
1162
1163 struct armem *newp = alloca (sizeof (struct armem));
1164 newp->old_off = elf_getaroff (subelf);
1165 newp->size = arhdr->ar_size;
1166 newp->sec = arhdr->ar_date;
1167 newp->mem = NULL;
1168
1169 /* Remember long file names. */
1170 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
1171
1172 /* Check whether this is a file we are looking for. */
1173 if (oper != oper_qappend)
1174 {
1175 /* Check whether this is the member used as the insert point. */
1176 if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
1177 {
1178 /* Note that all == NULL means insert at the beginning. */
1179 if (ipos == ipos_before)
1180 after_memberelem = all;
1181 else
1182 after_memberelem = newp;
1183 member = NULL;
1184 }
1185
1186 ENTRY entry;
1187 entry.key = arhdr->ar_name;
1188 ENTRY *res = hsearch (entry, FIND);
1189 if (res != NULL && found[(char **) res->data - argv] == NULL)
1190 {
1191 found[(char **) res->data - argv] = newp;
1192
1193 /* If we insert before or after a certain element move
1194 all files to a special list. */
1195 if (unlikely (ipos != ipos_none || oper == oper_move))
1196 {
1197 if (after_memberelem == newp)
1198 /* Since we remove this element even though we should
1199 insert everything after it, we in fact insert
1200 everything after the previous element. */
1201 after_memberelem = all;
1202
1203 goto next;
1204 }
1205 }
1206 }
1207
1208 if (all == NULL)
1209 all = newp->next = newp;
1210 else
1211 {
1212 newp->next = all->next;
1213 all = all->next = newp;
1214 }
1215
1216 next:
1217 cmd = elf_next (subelf);
1218 if (elf_end (subelf) != 0)
1219 error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1220 }
1221
1222 if (oper != oper_qappend)
1223 hdestroy ();
1224
1225 no_old:
1226 if (member != NULL)
1227 error_exit (0, _("position member %s not found"),
1228 member);
1229
1230 if (oper == oper_move)
1231 {
1232 /* Make sure all requested elements are found in the archive. */
1233 for (int cnt = 0; cnt < argc; ++cnt)
1234 {
1235 if (found[cnt] == NULL)
1236 {
1237 fprintf (stderr, _("%s: no entry %s in archive!\n"),
1238 program_invocation_short_name, argv[cnt]);
1239 status = 1;
1240 }
1241
1242 if (verbose)
1243 printf ("m - %s\n", argv[cnt]);
1244 }
1245 }
1246 else
1247 {
1248 /* Open all the new files, get their sizes and add all symbols. */
1249 for (int cnt = 0; cnt < argc; ++cnt)
1250 {
1251 const char *bname = basename (argv[cnt]);
1252 size_t bnamelen = strlen (bname);
1253 if (found[cnt] == NULL)
1254 {
1255 found[cnt] = alloca (sizeof (struct armem));
1256 found[cnt]->old_off = -1;
1257
1258 remember_long_name (found[cnt], bname, bnamelen);
1259 }
1260
1261 struct stat newst;
1262 Elf *newelf;
1263 int newfd = open (argv[cnt], O_RDONLY);
1264 if (newfd == -1)
1265 {
1266 error (0, errno, _("cannot open %s"), argv[cnt]);
1267 status = 1;
1268 }
1269 else if (fstat (newfd, &newst) == -1)
1270 {
1271 error (0, errno, _("cannot stat %s"), argv[cnt]);
1272 close (newfd);
1273 status = 1;
1274 }
1275 else if (!S_ISREG (newst.st_mode))
1276 {
1277 error (0, errno, _("%s is no regular file"), argv[cnt]);
1278 close (newfd);
1279 status = 1;
1280 }
1281 else if (update_newer
1282 && found[cnt]->old_off != -1l
1283 && found[cnt]->sec > st.st_mtime)
1284 /* Do nothing, the file in the archive is younger. */
1285 close (newfd);
1286 else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
1287 == NULL)
1288 {
1289 fprintf (stderr,
1290 _("cannot get ELF descriptor for %s: %s\n"),
1291 argv[cnt], elf_errmsg (-1));
1292 status = 1;
1293 }
1294 else
1295 {
1296 if (verbose)
1297 printf ("%c - %s\n",
1298 found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
1299
1300 found[cnt]->elf = newelf;
1301 found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime;
1302 found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid;
1303 found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid;
1304 found[cnt]->mode = newst.st_mode;
1305 found[cnt]->name = bname;
1306
1307 found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
1308 if (found[cnt]->mem == NULL
1309 || elf_cntl (newelf, ELF_C_FDDONE) != 0)
1310 error_exit (0, _("cannot read %s: %s"),
1311 argv[cnt], elf_errmsg (-1));
1312
1313 close (newfd);
1314
1315 if (found[cnt]->old_off != -1l)
1316 /* Remember long file names. */
1317 remember_long_name (found[cnt], bname, bnamelen);
1318 }
1319 }
1320 }
1321
1322 if (status != 0)
1323 {
1324 elf_end (elf);
1325
1326 arlib_fini ();
1327
1328 close (fd);
1329
1330 return status;
1331 }
1332
1333 /* If we have no entry point so far add at the end. AFTER_MEMBERELEM
1334 being NULL when adding before an entry means add at the beginning. */
1335 if (ipos != ipos_before && after_memberelem == NULL)
1336 after_memberelem = all;
1337
1338 /* Convert the circular list into a normal list first. */
1339 if (all != NULL)
1340 {
1341 struct armem *tmp = all;
1342 all = all->next;
1343 tmp->next = NULL;
1344 }
1345
1346 struct armem *last_added = after_memberelem;
1347 for (int cnt = 0; cnt < argc; ++cnt)
1348 if (oper != oper_replace || found[cnt]->old_off == -1)
1349 {
1350 if (last_added == NULL)
1351 {
1352 found[cnt]->next = all;
1353 last_added = all = found[cnt];
1354 }
1355 else
1356 {
1357 found[cnt]->next = last_added->next;
1358 last_added = last_added->next = found[cnt];
1359 }
1360 }
1361
1362 /* Finally compute the offset and add the symbols for the files
1363 after the insert point. */
1364 if (likely (all != NULL))
1365 for (struct armem *memp = all; memp != NULL; memp = memp->next)
1366 {
1367 memp->off = cur_off;
1368
1369 if (memp->mem == NULL)
1370 {
1371 Elf_Arhdr *arhdr;
1372 /* Fake initializing arhdr and subelf to keep gcc calm. */
1373 asm ("" : "=m" (arhdr), "=m" (subelf));
1374 if (elf_rand (elf, memp->old_off) == 0
1375 || (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL
1376 || (arhdr = elf_getarhdr (subelf)) == NULL)
1377 /* This should never happen since we already looked at the
1378 archive content. But who knows... */
1379 error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1380
1381 arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
1382
1383 elf_end (subelf);
1384 }
1385 else
1386 arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
1387
1388 cur_off += (((memp->size + 1) & ~((off_t) 1))
1389 + sizeof (struct ar_hdr));
1390 }
1391
1392 /* Now we have all the information for the symbol table and long
1393 file name table. Construct the final layout. */
1394 arlib_finalize ();
1395
1396 /* Create a new, temporary file in the same directory as the
1397 original file. */
1398 char tmpfname[strlen (arfname) + 7];
1399 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1400 int newfd;
1401 if (fd != -1)
1402 newfd = mkstemp (tmpfname);
1403 else
1404 {
1405 newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE);
1406 if (newfd == -1 && errno == EEXIST)
1407 /* Bah, first the file did not exist, now it does. Restart. */
1408 return do_oper_insert (oper, arfname, argv, argc, member);
1409 }
1410 if (unlikely (newfd == -1))
1411 goto nonew;
1412
1413 /* Create the header. */
1414 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1415 {
1416 nonew_unlink:
1417 if (fd != -1)
1418 {
1419 // XXX Use /prof/self/fd/%d ???
1420 unlink (tmpfname);
1421 if (newfd != -1)
1422 close (newfd);
1423 }
1424 nonew:
1425 error (0, errno, _("cannot create new file"));
1426 status = 1;
1427 goto errout;
1428 }
1429
1430 /* If the new archive is not empty we actually have something to do. */
1431 if (likely (all != NULL))
1432 {
1433 /* Write the symbol table or the long file name table or both. */
1434 if (symtab.symsnamelen != 0
1435 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1436 != (ssize_t) symtab.symsofflen)
1437 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1438 != (ssize_t) symtab.symsnamelen)))
1439 goto nonew_unlink;
1440
1441 if (symtab.longnameslen > sizeof (struct ar_hdr)
1442 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1443 != (ssize_t) symtab.longnameslen))
1444 goto nonew_unlink;
1445
1446 off_t start = -1;
1447 off_t len = -1;
1448
1449 while (all != NULL)
1450 {
1451 if (all->mem != NULL)
1452 {
1453 /* This is a new file. If there is anything from the
1454 archive left to be written do it now. */
1455 if (start != -1 && copy_content (elf, newfd, start, len))
1456 goto nonew_unlink;
1457
1458 start = -1;
1459 len = -1;
1460
1461 /* Create the header. */
1462 struct ar_hdr arhdr;
1463 /* The ar_name is not actually zero terminated, but we
1464 need that for snprintf. Also if the name is too
1465 long, then the string starts with '/' plus an index
1466 off number (decimal). */
1467 char tmpbuf[sizeof (arhdr.ar_name) + 2];
1468 if (all->long_name_off == -1)
1469 {
1470 size_t namelen = strlen (all->name);
1471 char *p = mempcpy (arhdr.ar_name, all->name, namelen);
1472 *p++ = '/';
1473 memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
1474 }
1475 else
1476 {
1477 snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
1478 (int) sizeof (arhdr.ar_name), all->long_name_off);
1479 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
1480 }
1481
1482 if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
1483 all->sec))
1484 {
1485 error (0, errno, _("cannot represent ar_date"));
1486 goto nonew_unlink;
1487 }
1488 if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid),
1489 all->uid))
1490 {
1491 error (0, errno, _("cannot represent ar_uid"));
1492 goto nonew_unlink;
1493 }
1494 if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid),
1495 all->gid))
1496 {
1497 error (0, errno, _("cannot represent ar_gid"));
1498 goto nonew_unlink;
1499 }
1500 if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode),
1501 all->mode))
1502 {
1503 error (0, errno, _("cannot represent ar_mode"));
1504 goto nonew_unlink;
1505 }
1506 if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
1507 all->size))
1508 {
1509 error (0, errno, _("cannot represent ar_size"));
1510 goto nonew_unlink;
1511 }
1512 memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
1513
1514 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
1515 != sizeof (arhdr)))
1516 goto nonew_unlink;
1517
1518 /* Now the file itself. */
1519 if (unlikely (write_retry (newfd, all->mem, all->size)
1520 != (off_t) all->size))
1521 goto nonew_unlink;
1522
1523 /* Pad the file if its size is odd. */
1524 if ((all->size & 1) != 0)
1525 if (unlikely (write_retry (newfd, "\n", 1) != 1))
1526 goto nonew_unlink;
1527 }
1528 else
1529 {
1530 /* This is a member from the archive. */
1531 if (write_member (all, &start, &len, elf, cur_off, newfd)
1532 != 0)
1533 goto nonew_unlink;
1534 }
1535
1536 all = all->next;
1537 }
1538
1539 /* Write the last part. */
1540 if (start != -1 && copy_content (elf, newfd, start, len))
1541 goto nonew_unlink;
1542 }
1543
1544 /* Set the mode of the new file to the same values the original file
1545 has. */
1546 if (fd != -1)
1547 {
1548 /* Never complain about fchown failing. But do it before
1549 setting the modes, or they might be reset/ignored if the
1550 owner is wrong. */
1551 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1552 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1553 || close (newfd) != 0)
1554 goto nonew_unlink;
1555 newfd = -1;
1556 if (rename (tmpfname, arfname) != 0)
1557 goto nonew_unlink;
1558 }
1559
1560 errout:
1561 for (int cnt = 0; cnt < argc; ++cnt)
1562 elf_end (found[cnt]->elf);
1563
1564 elf_end (elf);
1565
1566 arlib_fini ();
1567
1568 if (fd != -1)
1569 close (fd);
1570
1571 if (newfd != -1)
1572 close (newfd);
1573
1574 return status;
1575 }
1576
1577
1578 #include "debugpred.h"
1579