1 /* Create, modify, and extract from archives.
2 Copyright (C) 2005-2012 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2005.
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.
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.
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.
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>. */
43 #include <stdio_ext.h>
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;
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,
65 static int do_oper_insert (int oper, const char *arfname, char **argv,
66 int argc, const char *member);
69 /* Bug report address. */
70 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
73 /* Definitions of arguments for argp functions. */
74 static const struct argp_option options[] =
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 },
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 },
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 },
90 N_("Do not replace existing files with extracted files."), 0 },
91 { NULL, 'T', NULL, 0, N_("Allow filename to be truncated if necessary."),
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."),
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 },
103 { NULL, 0, NULL, 0, NULL, 0 }
106 /* Short description of program. */
107 static const char doc[] = N_("Create, modify, and extract from archives.");
109 /* Strings for arguments in help texts. */
110 static const char args_doc[] = N_("[MEMBER] [COUNT] ARCHIVE [FILE...]");
112 /* Prototype for option handler. */
113 static error_t parse_opt (int key, char *arg, struct argp_state *state);
115 /* Data structure to communicate with argp functions. */
116 static struct argp argp =
118 options, parse_opt, args_doc, doc, arlib_argp_children, NULL, NULL
122 /* What operation to perform. */
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;
149 main (int argc, char *argv[])
151 /* Make memory leak detection possible. */
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);
160 (void) setlocale (LC_ALL, "");
162 /* Make sure the message catalog can be found. */
163 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
165 /* Initialize the message catalog. */
166 (void) textdomain (PACKAGE_TARNAME);
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] != '-')
172 size_t len = strlen (argv[1]) + 1;
173 char *newp = alloca (len + 1);
175 memcpy (&newp[1], argv[1], len);
179 /* Parse and process arguments. */
181 (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL);
183 /* Tell the library which version we are expecting. */
184 (void) elf_version (EV_CURRENT);
186 /* Handle the [MEMBER] parameter. */
187 const char *member = NULL;
188 if (ipos != ipos_none)
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"));
195 if (remaining == argc)
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);
204 member = argv[remaining++];
207 /* Handle the [COUNT] parameter. */
208 long int instance = -1;
209 if (instance_specifed)
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"));
216 if (remaining == argc)
218 error (0, 0, gettext ("COUNT parameter required"));
219 argp_help (&argp, stderr, ARGP_HELP_SEE,
220 program_invocation_short_name);
226 if (((instance = strtol (argv[remaining], &endp, 10)) == LONG_MAX
230 error (1, 0, gettext ("invalid COUNT parameter %s"), argv[remaining]);
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');
240 /* There must at least be one more parameter specifying the archive. */
241 if (remaining == argc)
243 error (0, 0, gettext ("archive name required"));
244 argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
248 const char *arfname = argv[remaining++];
256 error (0, 0, gettext ("command option required"));
257 argp_help (&argp, stderr, ARGP_HELP_STD_ERR,
258 program_invocation_short_name);
264 status = do_oper_extract (operation, arfname, argv, argc, -1);
268 status = do_oper_extract (operation, arfname, argv, argc, instance);
272 status = do_oper_delete (arfname, argv, argc, instance);
278 status = do_oper_insert (operation, arfname, argv, argc, member);
282 assert (! "should not happen");
291 /* Print the version information. */
293 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
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\
301 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
305 /* Handle program arguments. */
307 parse_opt (int key, char *arg __attribute__ ((unused)),
308 struct argp_state *state __attribute__ ((unused)))
319 if (operation != oper_none)
321 error (0, 0, gettext ("More than one operation specified"));
322 argp_help (&argp, stderr, ARGP_HELP_SEE,
323 program_invocation_short_name);
330 operation = oper_delete;
333 operation = oper_move;
336 operation = oper_print;
339 operation = oper_qappend;
342 operation = oper_replace;
345 operation = oper_list;
348 operation = oper_extract;
363 suppress_create_msg = true;
367 dont_replace_existing = true;
371 instance_specifed = true;
375 preserve_dates = true;
387 allow_truncate_fname = true;
399 return ARGP_ERR_UNKNOWN;
406 open_archive (const char *arfname, int flags, int mode, Elf **elf,
407 struct stat *st, bool miss_allowed)
409 int fd = open (arfname, flags, mode);
415 error (EXIT_FAILURE, errno, gettext ("cannot open archive '%s'"),
421 Elf_Cmd cmd = flags == O_RDONLY ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP;
423 *elf = elf_begin (fd, cmd, NULL);
425 error (EXIT_FAILURE, 0, gettext ("cannot open archive '%s': %s"),
426 arfname, elf_errmsg (-1));
428 if (flags == O_RDONLY && elf_kind (*elf) != ELF_K_AR)
429 error (EXIT_FAILURE, 0, gettext ("%s: not an archive file"), arfname);
432 if (st != NULL && fstat (fd, st) != 0)
433 error (EXIT_FAILURE, errno, gettext ("cannot stat archive '%s'"),
441 not_found (int argc, char *argv[argc], bool found[argc])
443 for (int i = 0; i < argc; ++i)
445 printf (gettext ("no entry %s in archive\n"), argv[i]);
450 copy_content (Elf *elf, int newfd, off_t off, size_t n)
453 char *rawfile = elf_rawfile (elf, &len);
455 assert (off + n <= len);
457 /* Tell the kernel we will read all the pages sequentially. */
458 size_t ps = sysconf (_SC_PAGESIZE);
460 posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL);
462 return write_retry (newfd, rawfile + off, n) != (ssize_t) n;
467 do_oper_extract (int oper, const char *arfname, char **argv, int argc,
471 memset (found, '\0', sizeof (found));
474 inline bool should_truncate_fname (void)
476 if (errno == ENAMETOOLONG && allow_truncate_fname)
480 long int len = pathconf (".", _PC_NAME_MAX);
484 return name_max != 0;
489 off_t index_off = -1;
490 size_t index_size = 0;
491 off_t cur_off = SARMAG;
495 int fd = open_archive (arfname, O_RDONLY, 0, &elf, NULL, false);
497 if (hcreate (2 * argc) == 0)
498 error (EXIT_FAILURE, errno, gettext ("cannot create hash table"));
500 for (int cnt = 0; cnt < argc; ++cnt)
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"));
511 if (fstat (fd, &st) != 0)
513 error (0, errno, gettext ("cannot stat '%s'"), arfname);
520 Elf_Cmd cmd = ELF_C_READ_MMAP;
522 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
524 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
526 if (strcmp (arhdr->ar_name, "/") == 0)
528 index_off = elf_getaroff (subelf);
529 index_size = arhdr->ar_size;
532 if (strcmp (arhdr->ar_name, "//") == 0)
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));
542 bool do_extract = argc <= 0;
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;
557 if (oper == oper_print)
559 printf ("\n<%s>\n\n", arhdr->ar_name);
561 /* We have to flush now because now we use the descriptor
565 else if (oper == oper_list)
568 strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y",
569 localtime (&arhdr->ar_date));
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' : '-'),
589 (uintmax_t) arhdr->ar_size,
594 printf ("x - %s\n", arhdr->ar_name);
597 if (oper == oper_list)
600 puts (arhdr->ar_name);
606 char *data = elf_rawfile (subelf, &nleft);
609 error (0, 0, gettext ("cannot read content of %s: %s"),
610 arhdr->ar_name, elf_errmsg (-1));
616 char tempfname[] = "XXXXXX";
617 bool use_mkstemp = true;
619 if (oper == oper_print)
623 xfd = mkstemp (tempfname);
624 if (unlikely (xfd == -1))
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)
633 xfd = open (arhdr->ar_name, flags, 0600);
634 if (unlikely (xfd == -1))
636 int printlen = INT_MAX;
638 if (should_truncate_fname ())
640 /* Try to truncate the name. First find out by how
643 char truncfname[name_max + 1];
644 *((char *) mempcpy (truncfname, arhdr->ar_name,
647 xfd = open (truncfname, flags, 0600);
652 error (0, errno, gettext ("cannot open %.*s"),
653 (int) printlen, arhdr->ar_name);
664 while ((n = TEMP_FAILURE_RETRY (write (xfd, data, nleft))) != -1)
672 if (unlikely (n == -1))
674 error (0, errno, gettext ("failed to write %s"), arhdr->ar_name);
681 if (oper != oper_print)
683 /* Fix up the mode. */
684 if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0))
686 error (0, errno, gettext ("cannot change mode of %s"),
693 struct timeval tv[2];
694 tv[0].tv_sec = arhdr->ar_date;
696 tv[1].tv_sec = arhdr->ar_date;
699 if (unlikely (futimes (xfd, tv) != 0))
702 gettext ("cannot change modification time of %s"),
708 /* If we used a temporary file, move it do the right
714 if (dont_replace_existing)
716 r = link (tempfname, arhdr->ar_name);
721 r = rename (tempfname, arhdr->ar_name);
723 if (unlikely (r) != 0)
725 int printlen = INT_MAX;
727 if (should_truncate_fname ())
729 /* Try to truncate the name. First find out by how
732 char truncfname[name_max + 1];
733 *((char *) mempcpy (truncfname, arhdr->ar_name,
736 if (dont_replace_existing)
738 r = link (tempfname, truncfname);
743 r = rename (tempfname, truncfname);
748 error (0, errno, gettext ("\
749 cannot rename temporary file to %.*s"),
750 printlen, arhdr->ar_name);
762 cmd = elf_next (subelf);
763 if (elf_end (subelf) != 0)
764 error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
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))
778 char tmpfname[strlen (arfname) + 7];
779 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
780 int newfd = mkstemp (tmpfname);
781 if (unlikely (newfd == -1))
784 error (0, errno, gettext ("cannot create new file"));
789 /* Create the header. */
790 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
792 // XXX Use /prof/self/fd/%d ???
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. */
805 rest_off = (index_off + sizeof (struct ar_hdr)
806 + ((index_size + 1) & ~1ul));
810 if ((symtab.symsnamelen != 0
811 && ((write_retry (newfd, symtab.symsoff,
813 != (ssize_t) symtab.symsofflen)
814 || (write_retry (newfd, symtab.symsname,
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,
829 || (newfd = -1, rename (tmpfname, arfname) != 0))
839 not_found (argc, argv, found);
850 long int long_name_off;
863 write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf,
864 off_t end_off, int newfd)
867 char tmpbuf[sizeof (arhdr.ar_name) + 1];
869 bool changed_header = memb->long_name_off != -1;
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));
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;
882 /* If the files are adjacent in the old file extend the range. */
883 if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off)
885 /* Extend the current range. */
886 *lenp += (memb->next != NULL
887 ? memb->next->off : end_off) - memb->off;
891 /* Write out the old range. */
892 if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp))
895 *startp = memb->old_off;
896 *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off;
900 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
902 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
906 *startp += sizeof (struct ar_hdr);
907 assert ((size_t) *lenp >= sizeof (struct ar_hdr));
908 *lenp -= sizeof (struct ar_hdr);
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. */
917 remember_long_name (struct armem *mem, const char *name, size_t namelen)
919 mem->long_name_off = (namelen > MAX_AR_NAME_LEN
920 ? arlib_add_long_name (name, namelen)
925 do_oper_delete (const char *arfname, char **argv, int argc,
928 bool *found = alloca (sizeof (bool) * argc);
929 memset (found, '\0', sizeof (found));
931 /* List of the files we keep. */
932 struct armem *to_copy = NULL;
937 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false);
939 if (hcreate (2 * argc) == 0)
940 error (EXIT_FAILURE, errno, gettext ("cannot create hash table"));
942 for (int cnt = 0; cnt < argc; ++cnt)
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"));
952 off_t cur_off = SARMAG;
953 Elf_Cmd cmd = ELF_C_READ_MMAP;
955 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
957 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
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)
964 bool do_delete = argc <= 0;
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;
978 printf ("d - %s\n", arhdr->ar_name);
982 struct armem *newp = alloca (sizeof (struct armem));
983 newp->old_off = elf_getaroff (subelf);
986 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
987 + sizeof (struct ar_hdr));
990 to_copy = newp->next = newp;
993 newp->next = to_copy->next;
994 to_copy = to_copy->next = newp;
997 /* If we recreate the symbol table read the file's symbol
999 arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
1001 /* Remember long file names. */
1002 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
1006 cmd = elf_next (subelf);
1007 if (elf_end (subelf) != 0)
1008 error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
1015 /* Create a new, temporary file in the same directory as the
1017 char tmpfname[strlen (arfname) + 7];
1018 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1019 int newfd = mkstemp (tmpfname);
1020 if (unlikely (newfd == -1))
1023 /* Create the header. */
1024 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1026 // XXX Use /prof/self/fd/%d ???
1032 error (0, errno, gettext ("cannot create new file"));
1037 /* If the archive is empty that is all we have to do. */
1038 if (likely (to_copy != NULL))
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)))
1048 if (symtab.longnameslen > sizeof (struct ar_hdr)
1049 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1050 != (ssize_t) symtab.longnameslen))
1053 /* NULL-terminate the list of files to copy. */
1054 struct armem *last = to_copy;
1055 to_copy = to_copy->next;
1062 if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
1064 while ((to_copy = to_copy->next) != NULL);
1066 /* Write the last part. */
1067 if (copy_content (elf, newfd, start, len))
1071 /* Set the mode of the new file to the same values the original file
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))); }),
1077 || (newfd = -1, rename (tmpfname, arfname) != 0))
1089 not_found (argc, argv, found);
1096 no0print (bool ofmt, char *buf, int bufsize, long int val)
1098 char tmpbuf[bufsize + 1];
1099 snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld", bufsize, val);
1100 memcpy (buf, tmpbuf, bufsize);
1105 do_oper_insert (int oper, const char *arfname, char **argv, int argc,
1111 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
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);
1121 /* Initialize early for no_old case. */
1122 off_t cur_off = SARMAG;
1126 if (!suppress_create_msg)
1127 fprintf (stderr, "%s: creating %s\n",
1128 program_invocation_short_name, arfname);
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
1137 if (oper != oper_qappend)
1139 if (hcreate (2 * argc) == 0)
1140 error (EXIT_FAILURE, errno, gettext ("cannot create hash table"));
1142 for (int cnt = 0; cnt < argc; ++cnt)
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"));
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;
1158 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
1160 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
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)
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;
1173 /* Remember long file names. */
1174 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
1176 /* Check whether this is a file we are looking for. */
1177 if (oper != oper_qappend)
1179 /* Check whether this is the member used as the insert point. */
1180 if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
1182 /* Note that all == NULL means insert at the beginning. */
1183 if (ipos == ipos_before)
1184 after_memberelem = all;
1186 after_memberelem = newp;
1191 entry.key = arhdr->ar_name;
1192 ENTRY *res = hsearch (entry, FIND);
1193 if (res != NULL && found[(char **) res->data - argv] == NULL)
1195 found[(char **) res->data - argv] = newp;
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))
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;
1213 all = newp->next = newp;
1216 newp->next = all->next;
1217 all = all->next = newp;
1221 cmd = elf_next (subelf);
1222 if (elf_end (subelf) != 0)
1223 error (EXIT_FAILURE, 0, "%s: %s", arfname, elf_errmsg (-1));
1226 if (oper != oper_qappend)
1231 error (EXIT_FAILURE, 0, gettext ("position member %s not found"),
1234 if (oper == oper_move)
1236 /* Make sure all requested elements are found in the archive. */
1237 for (int cnt = 0; cnt < argc; ++cnt)
1239 if (found[cnt] == NULL)
1241 fprintf (stderr, gettext ("%s: no entry %s in archive!\n"),
1242 program_invocation_short_name, argv[cnt]);
1247 printf ("m - %s\n", argv[cnt]);
1252 /* Open all the new files, get their sizes and add all symbols. */
1253 for (int cnt = 0; cnt < argc; ++cnt)
1255 const char *bname = basename (argv[cnt]);
1256 size_t bnamelen = strlen (bname);
1257 if (found[cnt] == NULL)
1259 found[cnt] = alloca (sizeof (struct armem));
1260 found[cnt]->old_off = -1;
1262 remember_long_name (found[cnt], bname, bnamelen);
1267 int newfd = open (argv[cnt], O_RDONLY);
1270 error (0, errno, gettext ("cannot open %s"), argv[cnt]);
1273 else if (fstat (newfd, &newst) == -1)
1275 error (0, errno, gettext ("cannot stat %s"), argv[cnt]);
1279 else if (!S_ISREG (newst.st_mode))
1281 error (0, errno, gettext ("%s is no regular file"), argv[cnt]);
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. */
1290 else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
1294 gettext ("cannot get ELF descriptor for %s: %s\n"),
1295 argv[cnt], elf_errmsg (-1));
1301 printf ("%c - %s\n",
1302 found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
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;
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));
1319 if (found[cnt]->old_off != -1l)
1320 /* Remember long file names. */
1321 remember_long_name (found[cnt], bname, bnamelen);
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;
1344 /* Convert the circular list into a normal list first. */
1347 struct armem *tmp = all;
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)
1356 if (last_added == NULL)
1358 found[cnt]->next = all;
1359 last_added = all = found[cnt];
1363 found[cnt]->next = last_added->next;
1364 last_added = last_added->next = found[cnt];
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)
1373 memp->off = cur_off;
1375 if (memp->mem == NULL)
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));
1387 arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
1392 arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
1394 cur_off += (((memp->size + 1) & ~((off_t) 1))
1395 + sizeof (struct ar_hdr));
1398 /* Now we have all the information for the symbol table and long
1399 file name table. Construct the final layout. */
1402 /* Create a new, temporary file in the same directory as the
1404 char tmpfname[strlen (arfname) + 7];
1405 strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1408 newfd = mkstemp (tmpfname);
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);
1416 if (unlikely (newfd == -1))
1419 /* Create the header. */
1420 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1425 // XXX Use /prof/self/fd/%d ???
1431 error (0, errno, gettext ("cannot create new file"));
1436 /* If the new archive is not empty we actually have something to do. */
1437 if (likely (all != NULL))
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)))
1447 if (symtab.longnameslen > sizeof (struct ar_hdr)
1448 && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1449 != (ssize_t) symtab.longnameslen))
1457 if (all->mem != NULL)
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))
1467 /* Create the header. */
1468 struct ar_hdr arhdr;
1469 char tmpbuf[sizeof (arhdr.ar_name) + 1];
1470 if (all->long_name_off == -1)
1472 size_t namelen = strlen (all->name);
1473 char *p = mempcpy (arhdr.ar_name, all->name, namelen);
1475 memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
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));
1484 no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
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),
1490 no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
1492 memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
1494 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
1498 /* Now the file itself. */
1499 if (unlikely (write_retry (newfd, all->mem, all->size)
1500 != (off_t) all->size))
1503 /* Pad the file if its size is odd. */
1504 if ((all->size & 1) != 0)
1505 if (unlikely (write_retry (newfd, "\n", 1) != 1))
1510 /* This is a member from the archive. */
1511 if (write_member (all, &start, &len, elf, cur_off, newfd)
1519 /* Write the last part. */
1520 if (start != -1 && copy_content (elf, newfd, start, len))
1524 /* Set the mode of the new file to the same values the original file
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))); }),
1531 || (newfd = -1, rename (tmpfname, arfname) != 0)))
1547 #include "debugpred.h"