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