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
498 if (strcmp (arhdr->ar_name, "/") == 0)
499 {
500 index_off = elf_getaroff (subelf);
501 index_size = arhdr->ar_size;
502 goto next;
503 }
504 if (strcmp (arhdr->ar_name, "//") == 0)
505 goto next;
506
507 if (force_symtab)
508 {
509 arlib_add_symbols (elf, arfname, arhdr->ar_name, cur_off);
510 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
511 + sizeof (struct ar_hdr));
512 }
513
514 bool do_extract = argc <= 0;
515 if (!do_extract)
516 {
517 ENTRY entry;
518 entry.key = arhdr->ar_name;
519 ENTRY *res = hsearch (entry, FIND);
520 if (res != NULL && (instance < 0 || --instance == 0)
521 && !found[(char **) res->data - argv])
522 found[(char **) res->data - argv] = do_extract = true;
523 }
524
525 if (do_extract)
526 {
527 if (verbose)
528 {
529 if (oper == oper_print)
530 {
531 printf ("\n<%s>\n\n", arhdr->ar_name);
532
533 /* We have to flush now because now we use the descriptor
534 directly. */
535 fflush (stdout);
536 }
537 else if (oper == oper_list)
538 {
539 char datestr[100];
540 struct tm *tp = localtime (&arhdr->ar_date);
541 if (tp == NULL)
542 {
543 time_t time = 0;
544 tp = localtime (&time);
545 }
546
547 strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y", tp);
548
549 printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n",
550 (arhdr->ar_mode & S_IRUSR) ? 'r' : '-',
551 (arhdr->ar_mode & S_IWUSR) ? 'w' : '-',
552 (arhdr->ar_mode & S_IXUSR)
553 ? ((arhdr->ar_mode & S_ISUID) ? 's' : 'x')
554 : ((arhdr->ar_mode & S_ISUID) ? 'S' : '-'),
555 (arhdr->ar_mode & S_IRGRP) ? 'r' : '-',
556 (arhdr->ar_mode & S_IWGRP) ? 'w' : '-',
557 (arhdr->ar_mode & S_IXGRP)
558 ? ((arhdr->ar_mode & S_ISGID) ? 's' : 'x')
559 : ((arhdr->ar_mode & S_ISGID) ? 'S' : '-'),
560 (arhdr->ar_mode & S_IROTH) ? 'r' : '-',
561 (arhdr->ar_mode & S_IWOTH) ? 'w' : '-',
562 (arhdr->ar_mode & S_IXOTH)
563 ? ((arhdr->ar_mode & S_ISVTX) ? 't' : 'x')
564 : ((arhdr->ar_mode & S_ISVTX) ? 'T' : '-'),
565 arhdr->ar_uid,
566 arhdr->ar_gid,
567 (uintmax_t) arhdr->ar_size,
568 datestr,
569 arhdr->ar_name);
570 }
571 else
572 printf ("x - %s\n", arhdr->ar_name);
573 }
574
575 if (oper == oper_list)
576 {
577 if (!verbose)
578 puts (arhdr->ar_name);
579
580 goto next;
581 }
582
583 size_t nleft;
584 char *data = elf_rawfile (subelf, &nleft);
585 if (data == NULL)
586 {
587 error (0, 0, _("cannot read content of %s: %s"),
588 arhdr->ar_name, elf_errmsg (-1));
589 status = 1;
590 goto next;
591 }
592
593 int xfd;
594 char tempfname[] = "XXXXXX";
595 bool use_mkstemp = true;
596
597 if (oper == oper_print)
598 xfd = STDOUT_FILENO;
599 else
600 {
601 xfd = mkstemp (tempfname);
602 if (unlikely (xfd == -1))
603 {
604 /* We cannot create a temporary file. Try to overwrite
605 the file or create it if it does not exist. */
606 int flags = O_WRONLY | O_CREAT;
607 if (dont_replace_existing)
608 flags |= O_EXCL;
609 else
610 flags |= O_TRUNC;
611 xfd = open (arhdr->ar_name, flags, 0600);
612 if (unlikely (xfd == -1))
613 {
614 int printlen = INT_MAX;
615
616 if (should_truncate_fname (&name_max))
617 {
618 /* Try to truncate the name. First find out by how
619 much. */
620 printlen = name_max;
621 char truncfname[name_max + 1];
622 *((char *) mempcpy (truncfname, arhdr->ar_name,
623 name_max)) = '\0';
624
625 xfd = open (truncfname, flags, 0600);
626 }
627
628 if (xfd == -1)
629 {
630 error (0, errno, _("cannot open %.*s"),
631 (int) printlen, arhdr->ar_name);
632 status = 1;
633 goto next;
634 }
635 }
636
637 use_mkstemp = false;
638 }
639 }
640
641 ssize_t n;
642 while ((n = TEMP_FAILURE_RETRY (write (xfd, data, nleft))) != -1)
643 {
644 nleft -= n;
645 if (nleft == 0)
646 break;
647 data += n;
648 }
649
650 if (unlikely (n == -1))
651 {
652 error (0, errno, _("failed to write %s"), arhdr->ar_name);
653 status = 1;
654 unlink (tempfname);
655 close (xfd);
656 goto next;
657 }
658
659 if (oper != oper_print)
660 {
661 /* Fix up the mode. */
662 if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0))
663 {
664 error (0, errno, _("cannot change mode of %s"),
665 arhdr->ar_name);
666 status = 0;
667 }
668
669 if (preserve_dates)
670 {
671 struct timespec tv[2];
672 tv[0].tv_sec = arhdr->ar_date;
673 tv[0].tv_nsec = 0;
674 tv[1].tv_sec = arhdr->ar_date;
675 tv[1].tv_nsec = 0;
676
677 if (unlikely (futimens (xfd, tv) != 0))
678 {
679 error (0, errno,
680 _("cannot change modification time of %s"),
681 arhdr->ar_name);
682 status = 1;
683 }
684 }
685
686 /* If we used a temporary file, move it do the right
687 name now. */
688 if (use_mkstemp)
689 {
690 int r;
691
692 if (dont_replace_existing)
693 {
694 r = link (tempfname, arhdr->ar_name);
695 if (likely (r == 0))
696 unlink (tempfname);
697 }
698 else
699 r = rename (tempfname, arhdr->ar_name);
700
701 if (unlikely (r) != 0)
702 {
703 int printlen = INT_MAX;
704
705 if (should_truncate_fname (&name_max))
706 {
707 /* Try to truncate the name. First find out by how
708 much. */
709 printlen = name_max;
710 char truncfname[name_max + 1];
711 *((char *) mempcpy (truncfname, arhdr->ar_name,
712 name_max)) = '\0';
713
714 if (dont_replace_existing)
715 {
716 r = link (tempfname, truncfname);
717 if (likely (r == 0))
718 unlink (tempfname);
719 }
720 else
721 r = rename (tempfname, truncfname);
722 }
723
724 if (r != 0)
725 {
726 error (0, errno, _("\
727 cannot rename temporary file to %.*s"),
728 printlen, arhdr->ar_name);
729 unlink (tempfname);
730 status = 1;
731 }
732 }
733 }
734
735 close (xfd);
736 }
737 }
738
739 next:
740 cmd = elf_next (subelf);
741 if (elf_end (subelf) != 0)
742 error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
743 }
744
745 hdestroy ();
746
747 if (force_symtab)
748 {
749 arlib_finalize ();
750
751 if (symtab.symsnamelen != 0
752 /* We have to rewrite the file also if it initially had an index
753 but now does not need one anymore. */
754 || (symtab.symsnamelen == 0 && index_size != 0))
755 {
756 char tmpfname[strlen (arfname) + 7];
757 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
758 int newfd = mkstemp (tmpfname);
759 if (unlikely (newfd == -1))
760 {
761 nonew:
762 error (0, errno, _("cannot create new file"));
763 status = 1;
764 }
765 else
766 {
767 /* Create the header. */
768 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
769 {
770 // XXX Use /prof/self/fd/%d ???
771 nonew_unlink:
772 unlink (tmpfname);
773 if (newfd != -1)
774 close (newfd);
775 goto nonew;
776 }
777
778 /* Create the new file. There are three parts as far we are
779 concerned: 1. original context before the index, 2. the
780 new index, 3. everything after the new index. */
781 off_t rest_off;
782 if (index_off != -1)
783 rest_off = (index_off + sizeof (struct ar_hdr)
784 + ((index_size + 1) & ~1ul));
785 else
786 rest_off = SARMAG;
787
788 if (symtab.symsnamelen != 0
789 && ((write_retry (newfd, symtab.symsoff,
790 symtab.symsofflen)
791 != (ssize_t) symtab.symsofflen)
792 || (write_retry (newfd, symtab.symsname,
793 symtab.symsnamelen)
794 != (ssize_t) symtab.symsnamelen)))
795 goto nonew_unlink;
796 /* Even if the original file had content before the
797 symbol table, we write it in the correct order. */
798 if ((index_off != SARMAG
799 && copy_content (elf, newfd, SARMAG, index_off - SARMAG))
800 || copy_content (elf, newfd, rest_off, st.st_size - rest_off))
801 goto nonew_unlink;
802
803 /* Never complain about fchown failing. */
804 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
805 /* Set the mode of the new file to the same values the
806 original file has. */
807 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
808 || close (newfd) != 0)
809 goto nonew_unlink;
810 newfd = -1;
811 if (rename (tmpfname, arfname) != 0)
812 goto nonew_unlink;
813 }
814 }
815 }
816
817 elf_end (elf);
818
819 close (fd);
820
821 not_found (argc, argv, found);
822
823 return status;
824 }
825
826
827 struct armem
828 {
829 off_t off;
830 off_t old_off;
831 size_t size;
832 long int long_name_off;
833 struct armem *next;
834 void *mem;
835 time_t sec;
836 uid_t uid;
837 gid_t gid;
838 mode_t mode;
839 const char *name;
840 Elf *elf;
841 };
842
843
844 static int
write_member(struct armem * memb,off_t * startp,off_t * lenp,Elf * elf,off_t end_off,int newfd)845 write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf,
846 off_t end_off, int newfd)
847 {
848 struct ar_hdr arhdr;
849 /* The ar_name is not actually zero terminated, but we need that for
850 snprintf. Also if the name is too long, then the string starts
851 with '/' plus an index off number (decimal). */
852 char tmpbuf[sizeof (arhdr.ar_name) + 2];
853
854 bool changed_header = memb->long_name_off != -1;
855 if (changed_header)
856 {
857 /* In case of a long file name we assume the archive header
858 changed and we write it here. */
859 memcpy (&arhdr, elf_rawfile (elf, NULL) + *startp, sizeof (arhdr));
860
861 snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
862 (int) sizeof (arhdr.ar_name), memb->long_name_off);
863 changed_header = memcmp (arhdr.ar_name, tmpbuf,
864 sizeof (arhdr.ar_name)) != 0;
865 }
866
867 /* If the files are adjacent in the old file extend the range. */
868 if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off)
869 {
870 /* Extend the current range. */
871 *lenp += (memb->next != NULL
872 ? memb->next->off : end_off) - memb->off;
873 return 0;
874 }
875
876 /* Write out the old range. */
877 if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp))
878 return -1;
879
880 *startp = memb->old_off;
881 *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off;
882
883 if (changed_header)
884 {
885 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
886
887 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
888 != sizeof (arhdr)))
889 return -1;
890
891 *startp += sizeof (struct ar_hdr);
892 assert ((size_t) *lenp >= sizeof (struct ar_hdr));
893 *lenp -= sizeof (struct ar_hdr);
894 }
895
896 return 0;
897 }
898
899 /* Store the name in the long name table if necessary.
900 Record its offset or -1 if we did not need to use the table. */
901 static void
remember_long_name(struct armem * mem,const char * name,size_t namelen)902 remember_long_name (struct armem *mem, const char *name, size_t namelen)
903 {
904 mem->long_name_off = (namelen > MAX_AR_NAME_LEN
905 ? arlib_add_long_name (name, namelen)
906 : -1l);
907 }
908
909 static int
do_oper_delete(const char * arfname,char ** argv,int argc,long int instance)910 do_oper_delete (const char *arfname, char **argv, int argc,
911 long int instance)
912 {
913 bool *found = alloca (sizeof (bool) * argc);
914 memset (found, '\0', sizeof (bool) * argc);
915
916 /* List of the files we keep. */
917 struct armem *to_copy = NULL;
918
919 int status = 0;
920 Elf *elf;
921 struct stat st;
922 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false);
923
924 if (hcreate (2 * argc) == 0)
925 error_exit (errno, _("cannot create hash table"));
926
927 for (int cnt = 0; cnt < argc; ++cnt)
928 {
929 ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
930 if (hsearch (entry, ENTER) == NULL)
931 error_exit (errno, _("cannot insert into hash table"));
932 }
933
934 arlib_init ();
935
936 off_t cur_off = SARMAG;
937 Elf_Cmd cmd = ELF_C_READ_MMAP;
938 Elf *subelf;
939 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
940 {
941 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
942
943 /* Ignore the symbol table and the long file name table here. */
944 if (strcmp (arhdr->ar_name, "/") == 0
945 || strcmp (arhdr->ar_name, "//") == 0)
946 goto next;
947
948 bool do_delete = argc <= 0;
949 if (!do_delete)
950 {
951 ENTRY entry;
952 entry.key = arhdr->ar_name;
953 ENTRY *res = hsearch (entry, FIND);
954 if (res != NULL && (instance < 0 || --instance == 0)
955 && !found[(char **) res->data - argv])
956 found[(char **) res->data - argv] = do_delete = true;
957 }
958
959 if (do_delete)
960 {
961 if (verbose)
962 printf ("d - %s\n", arhdr->ar_name);
963 }
964 else
965 {
966 struct armem *newp = alloca (sizeof (struct armem));
967 newp->old_off = elf_getaroff (subelf);
968 newp->off = cur_off;
969
970 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
971 + sizeof (struct ar_hdr));
972
973 if (to_copy == NULL)
974 to_copy = newp->next = newp;
975 else
976 {
977 newp->next = to_copy->next;
978 to_copy = to_copy->next = newp;
979 }
980
981 /* If we recreate the symbol table read the file's symbol
982 table now. */
983 arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
984
985 /* Remember long file names. */
986 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
987 }
988
989 next:
990 cmd = elf_next (subelf);
991 if (elf_end (subelf) != 0)
992 error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
993 }
994
995 arlib_finalize ();
996
997 hdestroy ();
998
999 /* Create a new, temporary file in the same directory as the
1000 original file. */
1001 char tmpfname[strlen (arfname) + 7];
1002 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1003 int newfd = mkstemp (tmpfname);
1004 if (unlikely (newfd == -1))
1005 goto nonew;
1006
1007 /* Create the header. */
1008 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1009 {
1010 // XXX Use /prof/self/fd/%d ???
1011 nonew_unlink:
1012 unlink (tmpfname);
1013 if (newfd != -1)
1014 close (newfd);
1015 nonew:
1016 error (0, errno, _("cannot create new file"));
1017 status = 1;
1018 goto errout;
1019 }
1020
1021 /* If the archive is empty that is all we have to do. */
1022 if (likely (to_copy != NULL))
1023 {
1024 /* Write the symbol table or the long file name table or both. */
1025 if (symtab.symsnamelen != 0
1026 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1027 != (ssize_t) symtab.symsofflen)
1028 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1029 != (ssize_t) symtab.symsnamelen)))
1030 goto nonew_unlink;
1031
1032 if (symtab.longnameslen > sizeof (struct ar_hdr)
1033 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1034 != (ssize_t) symtab.longnameslen))
1035 goto nonew_unlink;
1036
1037 /* NULL-terminate the list of files to copy. */
1038 struct armem *last = to_copy;
1039 to_copy = to_copy->next;
1040 last->next = NULL;
1041
1042 off_t start = -1;
1043 off_t len = -1;
1044
1045 do
1046 if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
1047 goto nonew_unlink;
1048 while ((to_copy = to_copy->next) != NULL);
1049
1050 /* Write the last part. */
1051 if (copy_content (elf, newfd, start, len))
1052 goto nonew_unlink;
1053 }
1054
1055 /* Set the mode of the new file to the same values the original file
1056 has. Never complain about fchown failing. But do it before
1057 setting the mode (which might be reset/ignored if the owner is
1058 wrong. */
1059 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1060 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1061 || close (newfd) != 0)
1062 goto nonew_unlink;
1063 newfd = -1;
1064 if (rename (tmpfname, arfname) != 0)
1065 goto nonew_unlink;
1066
1067 errout:
1068 elf_end (elf);
1069
1070 arlib_fini ();
1071
1072 close (fd);
1073
1074 not_found (argc, argv, found);
1075
1076 return status;
1077 }
1078
1079
1080 /* Prints the given value in the given buffer without a trailing zero char.
1081 Returns false if the given value doesn't fit in the given buffer. */
1082 static bool
no0print(bool ofmt,char * buf,int bufsize,long int val)1083 no0print (bool ofmt, char *buf, int bufsize, long int val)
1084 {
1085 char tmpbuf[bufsize + 1];
1086 int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld",
1087 bufsize, val);
1088 if (ret >= (int) sizeof (tmpbuf))
1089 return false;
1090 memcpy (buf, tmpbuf, bufsize);
1091 return true;
1092 }
1093
1094
1095 static int
do_oper_insert(int oper,const char * arfname,char ** argv,int argc,const char * member)1096 do_oper_insert (int oper, const char *arfname, char **argv, int argc,
1097 const char *member)
1098 {
1099 int status = 0;
1100 Elf *elf = NULL;
1101 struct stat st;
1102 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
1103
1104 /* List of the files we keep. */
1105 struct armem *all = NULL;
1106 struct armem *after_memberelem = NULL;
1107 struct armem **found = alloca (sizeof (*found) * argc);
1108 memset (found, '\0', sizeof (*found) * argc);
1109
1110 arlib_init ();
1111
1112 /* Initialize early for no_old case. */
1113 off_t cur_off = SARMAG;
1114
1115 if (fd == -1)
1116 {
1117 if (!suppress_create_msg)
1118 fprintf (stderr, "%s: creating %s\n",
1119 program_invocation_short_name, arfname);
1120
1121 goto no_old;
1122 }
1123
1124 /* Store the names of all files from the command line in a hash
1125 table so that we can match it. Note that when no file name is
1126 given we are basically doing nothing except recreating the
1127 index. */
1128 if (oper != oper_qappend)
1129 {
1130 if (hcreate (2 * argc) == 0)
1131 error_exit (errno, _("cannot create hash table"));
1132
1133 for (int cnt = 0; cnt < argc; ++cnt)
1134 {
1135 ENTRY entry;
1136 entry.key = full_path ? argv[cnt] : basename (argv[cnt]);
1137 entry.data = &argv[cnt];
1138 if (hsearch (entry, ENTER) == NULL)
1139 error_exit (errno, _("cannot insert into hash table"));
1140 }
1141 }
1142
1143 /* While iterating over the current content of the archive we must
1144 determine a number of things: which archive members to keep,
1145 which are replaced, and where to insert the new members. */
1146 Elf_Cmd cmd = ELF_C_READ_MMAP;
1147 Elf *subelf;
1148 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
1149 {
1150 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
1151
1152 /* Ignore the symbol table and the long file name table here. */
1153 if (strcmp (arhdr->ar_name, "/") == 0
1154 || strcmp (arhdr->ar_name, "//") == 0)
1155 goto next;
1156
1157 struct armem *newp = alloca (sizeof (struct armem));
1158 newp->old_off = elf_getaroff (subelf);
1159 newp->size = arhdr->ar_size;
1160 newp->sec = arhdr->ar_date;
1161 newp->mem = NULL;
1162
1163 /* Remember long file names. */
1164 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
1165
1166 /* Check whether this is a file we are looking for. */
1167 if (oper != oper_qappend)
1168 {
1169 /* Check whether this is the member used as the insert point. */
1170 if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
1171 {
1172 /* Note that all == NULL means insert at the beginning. */
1173 if (ipos == ipos_before)
1174 after_memberelem = all;
1175 else
1176 after_memberelem = newp;
1177 member = NULL;
1178 }
1179
1180 ENTRY entry;
1181 entry.key = arhdr->ar_name;
1182 ENTRY *res = hsearch (entry, FIND);
1183 if (res != NULL && found[(char **) res->data - argv] == NULL)
1184 {
1185 found[(char **) res->data - argv] = newp;
1186
1187 /* If we insert before or after a certain element move
1188 all files to a special list. */
1189 if (unlikely (ipos != ipos_none || oper == oper_move))
1190 {
1191 if (after_memberelem == newp)
1192 /* Since we remove this element even though we should
1193 insert everything after it, we in fact insert
1194 everything after the previous element. */
1195 after_memberelem = all;
1196
1197 goto next;
1198 }
1199 }
1200 }
1201
1202 if (all == NULL)
1203 all = newp->next = newp;
1204 else
1205 {
1206 newp->next = all->next;
1207 all = all->next = newp;
1208 }
1209
1210 next:
1211 cmd = elf_next (subelf);
1212 if (elf_end (subelf) != 0)
1213 error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1214 }
1215
1216 if (oper != oper_qappend)
1217 hdestroy ();
1218
1219 no_old:
1220 if (member != NULL)
1221 error_exit (0, _("position member %s not found"),
1222 member);
1223
1224 if (oper == oper_move)
1225 {
1226 /* Make sure all requested elements are found in the archive. */
1227 for (int cnt = 0; cnt < argc; ++cnt)
1228 {
1229 if (found[cnt] == NULL)
1230 {
1231 fprintf (stderr, _("%s: no entry %s in archive!\n"),
1232 program_invocation_short_name, argv[cnt]);
1233 status = 1;
1234 }
1235
1236 if (verbose)
1237 printf ("m - %s\n", argv[cnt]);
1238 }
1239 }
1240 else
1241 {
1242 /* Open all the new files, get their sizes and add all symbols. */
1243 for (int cnt = 0; cnt < argc; ++cnt)
1244 {
1245 const char *bname = basename (argv[cnt]);
1246 size_t bnamelen = strlen (bname);
1247 if (found[cnt] == NULL)
1248 {
1249 found[cnt] = alloca (sizeof (struct armem));
1250 found[cnt]->old_off = -1;
1251
1252 remember_long_name (found[cnt], bname, bnamelen);
1253 }
1254
1255 struct stat newst;
1256 Elf *newelf;
1257 int newfd = open (argv[cnt], O_RDONLY);
1258 if (newfd == -1)
1259 {
1260 error (0, errno, _("cannot open %s"), argv[cnt]);
1261 status = 1;
1262 }
1263 else if (fstat (newfd, &newst) == -1)
1264 {
1265 error (0, errno, _("cannot stat %s"), argv[cnt]);
1266 close (newfd);
1267 status = 1;
1268 }
1269 else if (!S_ISREG (newst.st_mode))
1270 {
1271 error (0, errno, _("%s is no regular file"), argv[cnt]);
1272 close (newfd);
1273 status = 1;
1274 }
1275 else if (update_newer
1276 && found[cnt]->old_off != -1l
1277 && found[cnt]->sec > st.st_mtime)
1278 /* Do nothing, the file in the archive is younger. */
1279 close (newfd);
1280 else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
1281 == NULL)
1282 {
1283 fprintf (stderr,
1284 _("cannot get ELF descriptor for %s: %s\n"),
1285 argv[cnt], elf_errmsg (-1));
1286 status = 1;
1287 }
1288 else
1289 {
1290 if (verbose)
1291 printf ("%c - %s\n",
1292 found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
1293
1294 found[cnt]->elf = newelf;
1295 found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime;
1296 found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid;
1297 found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid;
1298 found[cnt]->mode = newst.st_mode;
1299 found[cnt]->name = bname;
1300
1301 found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
1302 if (found[cnt]->mem == NULL
1303 || elf_cntl (newelf, ELF_C_FDDONE) != 0)
1304 error_exit (0, _("cannot read %s: %s"),
1305 argv[cnt], elf_errmsg (-1));
1306
1307 close (newfd);
1308
1309 if (found[cnt]->old_off != -1l)
1310 /* Remember long file names. */
1311 remember_long_name (found[cnt], bname, bnamelen);
1312 }
1313 }
1314 }
1315
1316 if (status != 0)
1317 {
1318 elf_end (elf);
1319
1320 arlib_fini ();
1321
1322 close (fd);
1323
1324 return status;
1325 }
1326
1327 /* If we have no entry point so far add at the end. AFTER_MEMBERELEM
1328 being NULL when adding before an entry means add at the beginning. */
1329 if (ipos != ipos_before && after_memberelem == NULL)
1330 after_memberelem = all;
1331
1332 /* Convert the circular list into a normal list first. */
1333 if (all != NULL)
1334 {
1335 struct armem *tmp = all;
1336 all = all->next;
1337 tmp->next = NULL;
1338 }
1339
1340 struct armem *last_added = after_memberelem;
1341 for (int cnt = 0; cnt < argc; ++cnt)
1342 if (oper != oper_replace || found[cnt]->old_off == -1)
1343 {
1344 if (last_added == NULL)
1345 {
1346 found[cnt]->next = all;
1347 last_added = all = found[cnt];
1348 }
1349 else
1350 {
1351 found[cnt]->next = last_added->next;
1352 last_added = last_added->next = found[cnt];
1353 }
1354 }
1355
1356 /* Finally compute the offset and add the symbols for the files
1357 after the insert point. */
1358 if (likely (all != NULL))
1359 for (struct armem *memp = all; memp != NULL; memp = memp->next)
1360 {
1361 memp->off = cur_off;
1362
1363 if (memp->mem == NULL)
1364 {
1365 Elf_Arhdr *arhdr;
1366 /* Fake initializing arhdr and subelf to keep gcc calm. */
1367 asm ("" : "=m" (arhdr), "=m" (subelf));
1368 if (elf_rand (elf, memp->old_off) == 0
1369 || (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL
1370 || (arhdr = elf_getarhdr (subelf)) == NULL)
1371 /* This should never happen since we already looked at the
1372 archive content. But who knows... */
1373 error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1374
1375 arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
1376
1377 elf_end (subelf);
1378 }
1379 else
1380 arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
1381
1382 cur_off += (((memp->size + 1) & ~((off_t) 1))
1383 + sizeof (struct ar_hdr));
1384 }
1385
1386 /* Now we have all the information for the symbol table and long
1387 file name table. Construct the final layout. */
1388 arlib_finalize ();
1389
1390 /* Create a new, temporary file in the same directory as the
1391 original file. */
1392 char tmpfname[strlen (arfname) + 7];
1393 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1394 int newfd;
1395 if (fd != -1)
1396 newfd = mkstemp (tmpfname);
1397 else
1398 {
1399 newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE);
1400 if (newfd == -1 && errno == EEXIST)
1401 /* Bah, first the file did not exist, now it does. Restart. */
1402 return do_oper_insert (oper, arfname, argv, argc, member);
1403 }
1404 if (unlikely (newfd == -1))
1405 goto nonew;
1406
1407 /* Create the header. */
1408 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1409 {
1410 nonew_unlink:
1411 if (fd != -1)
1412 {
1413 // XXX Use /prof/self/fd/%d ???
1414 unlink (tmpfname);
1415 if (newfd != -1)
1416 close (newfd);
1417 }
1418 nonew:
1419 error (0, errno, _("cannot create new file"));
1420 status = 1;
1421 goto errout;
1422 }
1423
1424 /* If the new archive is not empty we actually have something to do. */
1425 if (likely (all != NULL))
1426 {
1427 /* Write the symbol table or the long file name table or both. */
1428 if (symtab.symsnamelen != 0
1429 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1430 != (ssize_t) symtab.symsofflen)
1431 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1432 != (ssize_t) symtab.symsnamelen)))
1433 goto nonew_unlink;
1434
1435 if (symtab.longnameslen > sizeof (struct ar_hdr)
1436 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1437 != (ssize_t) symtab.longnameslen))
1438 goto nonew_unlink;
1439
1440 off_t start = -1;
1441 off_t len = -1;
1442
1443 while (all != NULL)
1444 {
1445 if (all->mem != NULL)
1446 {
1447 /* This is a new file. If there is anything from the
1448 archive left to be written do it now. */
1449 if (start != -1 && copy_content (elf, newfd, start, len))
1450 goto nonew_unlink;
1451
1452 start = -1;
1453 len = -1;
1454
1455 /* Create the header. */
1456 struct ar_hdr arhdr;
1457 /* The ar_name is not actually zero terminated, but we
1458 need that for snprintf. Also if the name is too
1459 long, then the string starts with '/' plus an index
1460 off number (decimal). */
1461 char tmpbuf[sizeof (arhdr.ar_name) + 2];
1462 if (all->long_name_off == -1)
1463 {
1464 size_t namelen = strlen (all->name);
1465 char *p = mempcpy (arhdr.ar_name, all->name, namelen);
1466 *p++ = '/';
1467 memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
1468 }
1469 else
1470 {
1471 snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
1472 (int) sizeof (arhdr.ar_name), all->long_name_off);
1473 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
1474 }
1475
1476 if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
1477 all->sec))
1478 {
1479 error (0, errno, _("cannot represent ar_date"));
1480 goto nonew_unlink;
1481 }
1482 if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid),
1483 all->uid))
1484 {
1485 error (0, errno, _("cannot represent ar_uid"));
1486 goto nonew_unlink;
1487 }
1488 if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid),
1489 all->gid))
1490 {
1491 error (0, errno, _("cannot represent ar_gid"));
1492 goto nonew_unlink;
1493 }
1494 if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode),
1495 all->mode))
1496 {
1497 error (0, errno, _("cannot represent ar_mode"));
1498 goto nonew_unlink;
1499 }
1500 if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
1501 all->size))
1502 {
1503 error (0, errno, _("cannot represent ar_size"));
1504 goto nonew_unlink;
1505 }
1506 memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
1507
1508 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
1509 != sizeof (arhdr)))
1510 goto nonew_unlink;
1511
1512 /* Now the file itself. */
1513 if (unlikely (write_retry (newfd, all->mem, all->size)
1514 != (off_t) all->size))
1515 goto nonew_unlink;
1516
1517 /* Pad the file if its size is odd. */
1518 if ((all->size & 1) != 0)
1519 if (unlikely (write_retry (newfd, "\n", 1) != 1))
1520 goto nonew_unlink;
1521 }
1522 else
1523 {
1524 /* This is a member from the archive. */
1525 if (write_member (all, &start, &len, elf, cur_off, newfd)
1526 != 0)
1527 goto nonew_unlink;
1528 }
1529
1530 all = all->next;
1531 }
1532
1533 /* Write the last part. */
1534 if (start != -1 && copy_content (elf, newfd, start, len))
1535 goto nonew_unlink;
1536 }
1537
1538 /* Set the mode of the new file to the same values the original file
1539 has. */
1540 if (fd != -1)
1541 {
1542 /* Never complain about fchown failing. But do it before
1543 setting the modes, or they might be reset/ignored if the
1544 owner is wrong. */
1545 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1546 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1547 || close (newfd) != 0)
1548 goto nonew_unlink;
1549 newfd = -1;
1550 if (rename (tmpfname, arfname) != 0)
1551 goto nonew_unlink;
1552 }
1553
1554 errout:
1555 for (int cnt = 0; cnt < argc; ++cnt)
1556 elf_end (found[cnt]->elf);
1557
1558 elf_end (elf);
1559
1560 arlib_fini ();
1561
1562 if (fd != -1)
1563 close (fd);
1564
1565 if (newfd != -1)
1566 close (newfd);
1567
1568 return status;
1569 }
1570
1571
1572 #include "debugpred.h"
1573