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