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