diff options
Diffstat (limited to 'src/ar.c')
-rw-r--r-- | src/ar.c | 250 |
1 files changed, 105 insertions, 145 deletions
@@ -27,7 +27,6 @@ #include <libintl.h> #include <limits.h> #include <locale.h> -#include <search.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> @@ -392,14 +391,14 @@ open_archive (const char *arfname, int flags, int mode, Elf **elf, if (elf != NULL) { - Elf_Cmd cmd = flags == O_RDONLY ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP; + Elf_Cmd cmd = flags == (O_RDONLY | O_BINARY) ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP; *elf = elf_begin (fd, cmd, NULL); if (*elf == NULL) error (EXIT_FAILURE, 0, gettext ("cannot open archive '%s': %s"), arfname, elf_errmsg (-1)); - if (flags == O_RDONLY && elf_kind (*elf) != ELF_K_AR) + if (flags == (O_RDONLY | O_BINARY) && elf_kind (*elf) != ELF_K_AR) error (EXIT_FAILURE, 0, gettext ("%s: not an archive file"), arfname); } @@ -436,7 +435,6 @@ copy_content (Elf *elf, int newfd, off_t off, size_t n) return write_retry (newfd, rawfile + off, n) != (ssize_t) n; } - static int do_oper_extract (int oper, const char *arfname, char **argv, int argc, long int instance) @@ -447,16 +445,6 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, size_t name_max = 0; inline bool should_truncate_fname (void) { - if (errno == ENAMETOOLONG && allow_truncate_fname) - { - if (name_max == 0) - { - long int len = pathconf (".", _PC_NAME_MAX); - if (len > 0) - name_max = len; - } - return name_max != 0; - } return false; } @@ -466,18 +454,7 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, int status = 0; Elf *elf; - int fd = open_archive (arfname, O_RDONLY, 0, &elf, NULL, false); - - if (hcreate (2 * argc) == 0) - error (EXIT_FAILURE, errno, gettext ("cannot create hash table")); - - for (int cnt = 0; cnt < argc; ++cnt) - { - ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] }; - if (hsearch (entry, ENTER) == NULL) - error (EXIT_FAILURE, errno, - gettext ("cannot insert into hash table")); - } + int fd = open_archive (arfname, O_RDONLY | O_BINARY, 0, &elf, NULL, false); struct stat st; if (force_symtab) @@ -516,12 +493,15 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, bool do_extract = argc <= 0; if (!do_extract) { - ENTRY entry; - entry.key = arhdr->ar_name; - ENTRY *res = hsearch (entry, FIND); - if (res != NULL && (instance < 0 || instance-- == 0) - && !found[(char **) res->data - argv]) - found[(char **) res->data - argv] = do_extract = true; + for (int cnt = 0; cnt < argc; ++cnt) + { + if (!strcmp (arhdr->ar_name, argv[cnt])) + { + if ((instance < 0 || instance-- == 0) && !found[cnt]) + found[cnt] = do_extract = true; + break; + } + } } if (do_extract) @@ -546,7 +526,7 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, tp = localtime (&time); } - strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y", tp); + strftime (datestr, sizeof (datestr), "%b %d %H:%M %Y", tp); printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n", (arhdr->ar_mode & S_IRUSR) ? 'r' : '-', @@ -605,7 +585,7 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, { /* We cannot create a temporary file. Try to overwrite the file or create it if it does not exist. */ - int flags = O_WRONLY | O_CREAT; + int flags = O_WRONLY | O_BINARY | O_CREAT; if (dont_replace_existing) flags |= O_EXCL; else @@ -653,13 +633,14 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, { error (0, errno, gettext ("failed to write %s"), arhdr->ar_name); status = 1; - unlink (tempfname); close (xfd); + unlink (tempfname); goto next; } if (oper != oper_print) { +#if HAVE_DECL_FCHMOD /* Fix up the mode. */ if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0)) { @@ -667,26 +648,11 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, arhdr->ar_name); status = 0; } - - if (preserve_dates) - { - struct timespec tv[2]; - tv[0].tv_sec = arhdr->ar_date; - tv[0].tv_nsec = 0; - tv[1].tv_sec = arhdr->ar_date; - tv[1].tv_nsec = 0; - - if (unlikely (futimens (xfd, tv) != 0)) - { - error (0, errno, - gettext ("cannot change modification time of %s"), - arhdr->ar_name); - status = 1; - } - } +#endif /* If we used a temporary file, move it do the right name now. */ + close (xfd); if (use_mkstemp) { int r; @@ -698,7 +664,10 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, unlink (tempfname); } else - r = rename (tempfname, arhdr->ar_name); + { + unlink (arhdr->ar_name); + r = rename (tempfname, arhdr->ar_name); + } if (unlikely (r) != 0) { @@ -720,7 +689,10 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, unlink (tempfname); } else - r = rename (tempfname, truncfname); + { + unlink (truncfname); + r = rename (tempfname, truncfname); + } } if (r != 0) @@ -733,8 +705,6 @@ cannot rename temporary file to %.*s"), } } } - - close (xfd); } } @@ -744,8 +714,6 @@ cannot rename temporary file to %.*s"), error (1, 0, "%s: %s", arfname, elf_errmsg (-1)); } - hdestroy (); - if (force_symtab) { arlib_finalize (); @@ -771,9 +739,9 @@ cannot rename temporary file to %.*s"), { // XXX Use /prof/self/fd/%d ??? nonew_unlink: - unlink (tmpfname); if (newfd != -1) close (newfd); + unlink (tmpfname); goto nonew; } @@ -793,20 +761,25 @@ cannot rename temporary file to %.*s"), != (ssize_t) symtab.symsofflen) || (write_retry (newfd, symtab.symsname, symtab.symsnamelen) - != (ssize_t) symtab.symsnamelen))) + != (ssize_t) symtab.symsnamelen))) || /* Even if the original file had content before the symbol table, we write it in the correct order. */ - || (index_off != SARMAG - && copy_content (elf, newfd, SARMAG, index_off - SARMAG)) - || copy_content (elf, newfd, rest_off, st.st_size - rest_off) + (index_off != SARMAG + && copy_content (elf, newfd, SARMAG, index_off - SARMAG)) || + copy_content (elf, newfd, rest_off, st.st_size - rest_off) || +#if HAVE_DECL_FCHMOD /* Set the mode of the new file to the same values the original file has. */ - || fchmod (newfd, st.st_mode & ALLPERMS) != 0 + fchmod (newfd, st.st_mode & 07777) != 0 || +#endif + ( +#if HAVE_DECL_FCHOWN /* Never complain about fchown failing. */ - || (({asm ("" :: "r" (fchown (newfd, st.st_uid, + ({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }), - close (newfd) != 0) - || (newfd = -1, rename (tmpfname, arfname) != 0)) +#endif + close (newfd) != 0) || (newfd = -1, close (fd) != 0) || + (fd = -1, unlink (arfname), rename (tmpfname, arfname) != 0)) goto nonew_unlink; } } @@ -814,7 +787,8 @@ cannot rename temporary file to %.*s"), elf_end (elf); - close (fd); + if (fd != -1) + close (fd); not_found (argc, argv, found); @@ -917,18 +891,7 @@ do_oper_delete (const char *arfname, char **argv, int argc, int status = 0; Elf *elf; struct stat st; - int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false); - - if (hcreate (2 * argc) == 0) - error (EXIT_FAILURE, errno, gettext ("cannot create hash table")); - - for (int cnt = 0; cnt < argc; ++cnt) - { - ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] }; - if (hsearch (entry, ENTER) == NULL) - error (EXIT_FAILURE, errno, - gettext ("cannot insert into hash table")); - } + int fd = open_archive (arfname, O_RDONLY | O_BINARY, 0, &elf, &st, false); arlib_init (); @@ -947,12 +910,15 @@ do_oper_delete (const char *arfname, char **argv, int argc, bool do_delete = argc <= 0; if (!do_delete) { - ENTRY entry; - entry.key = arhdr->ar_name; - ENTRY *res = hsearch (entry, FIND); - if (res != NULL && (instance < 0 || instance-- == 0) - && !found[(char **) res->data - argv]) - found[(char **) res->data - argv] = do_delete = true; + for (int cnt = 0; cnt < argc; ++cnt) + { + if (!strcmp (arhdr->ar_name, argv[cnt])) + { + if ((instance < 0 || instance-- == 0) && !found[cnt]) + found[cnt] = do_delete = true; + break; + } + } } if (do_delete) @@ -993,8 +959,6 @@ do_oper_delete (const char *arfname, char **argv, int argc, arlib_finalize (); - hdestroy (); - /* Create a new, temporary file in the same directory as the original file. */ char tmpfname[strlen (arfname) + 7]; @@ -1051,13 +1015,19 @@ do_oper_delete (const char *arfname, char **argv, int argc, goto nonew_unlink; } - /* Set the mode of the new file to the same values the original file - has. */ - if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 + if ( +#if HAVE_DECL_FCHMOD + /* Set the mode of the new file to the same values the original file + has. */ + fchmod (newfd, st.st_mode & 07777) != 0 || +#endif + ( +#if HAVE_DECL_FCHOWN /* Never complain about fchown failing. */ - || (({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }), - close (newfd) != 0) - || (newfd = -1, rename (tmpfname, arfname) != 0)) + ({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }), +#endif + close (newfd) != 0) || (newfd = -1, close (fd) != 0) || + (fd = -1, unlink (arfname), rename (tmpfname, arfname) != 0)) goto nonew_unlink; errout: @@ -1065,7 +1035,8 @@ do_oper_delete (const char *arfname, char **argv, int argc, arlib_fini (); - close (fd); + if (fd != -1) + close (fd); not_found (argc, argv, found); @@ -1087,7 +1058,6 @@ no0print (bool ofmt, char *buf, int bufsize, long int val) return true; } - static int do_oper_insert (int oper, const char *arfname, char **argv, int argc, const char *member) @@ -1095,7 +1065,7 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, int status = 0; Elf *elf = NULL; struct stat st; - int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move); + int fd = open_archive (arfname, O_RDONLY | O_BINARY, 0, &elf, &st, oper != oper_move); /* List of the files we keep. */ struct armem *all = NULL; @@ -1117,26 +1087,6 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, goto no_old; } - /* Store the names of all files from the command line in a hash - table so that we can match it. Note that when no file name is - given we are basically doing nothing except recreating the - index. */ - if (oper != oper_qappend) - { - if (hcreate (2 * argc) == 0) - error (EXIT_FAILURE, errno, gettext ("cannot create hash table")); - - for (int cnt = 0; cnt < argc; ++cnt) - { - ENTRY entry; - entry.key = full_path ? argv[cnt] : basename (argv[cnt]); - entry.data = &argv[cnt]; - if (hsearch (entry, ENTER) == NULL) - error (EXIT_FAILURE, errno, - gettext ("cannot insert into hash table")); - } - } - /* While iterating over the current content of the archive we must determine a number of things: which archive members to keep, which are replaced, and where to insert the new members. */ @@ -1174,25 +1124,32 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, member = NULL; } - ENTRY entry; - entry.key = arhdr->ar_name; - ENTRY *res = hsearch (entry, FIND); - if (res != NULL && found[(char **) res->data - argv] == NULL) + const char *arhdr_basename = basename (arhdr->ar_name); + for (int cnt = 0; cnt < argc; ++cnt) { - found[(char **) res->data - argv] = newp; - - /* If we insert before or after a certain element move - all files to a special list. */ - if (unlikely (ipos != ipos_none || oper == oper_move)) - { - if (after_memberelem == newp) - /* Since we remove this element even though we should - insert everything after it, we in fact insert - everything after the previous element. */ - after_memberelem = all; + if (full_path && strcmp (arhdr_basename, basename (argv[cnt]))) + continue; + else if (!full_path && strcmp (arhdr->ar_name, argv[cnt])) + continue; + + if (found[cnt] == NULL) + { + found[cnt] = newp; + + /* If we insert before or after a certain element move + all files to a special list. */ + if (unlikely (ipos != ipos_none || oper == oper_move)) + { + if (after_memberelem == newp) + /* Since we remove this element even though we should + insert everything after it, we in fact insert + everything after the previous element. */ + after_memberelem = all; - goto next; + goto next; + } } + break; } } @@ -1210,9 +1167,6 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, error (EXIT_FAILURE, 0, "%s: %s", arfname, elf_errmsg (-1)); } - if (oper != oper_qappend) - hdestroy (); - no_old: if (member != NULL) error (EXIT_FAILURE, 0, gettext ("position member %s not found"), @@ -1251,7 +1205,7 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, struct stat newst; Elf *newelf; - int newfd = open (argv[cnt], O_RDONLY); + int newfd = open (argv[cnt], O_RDONLY | O_BINARY); if (newfd == -1) { error (0, errno, gettext ("cannot open %s"), argv[cnt]); @@ -1393,7 +1347,7 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, newfd = mkstemp (tmpfname); else { - newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE); + newfd = open (arfname, O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0666); if (newfd == -1 && errno == EEXIST) /* Bah, first the file did not exist, now it does. Restart. */ return do_oper_insert (oper, arfname, argv, argc, member); @@ -1408,9 +1362,9 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, if (fd != -1) { // XXX Use /prof/self/fd/%d ??? - unlink (tmpfname); if (newfd != -1) close (newfd); + unlink (tmpfname); } nonew: error (0, errno, gettext ("cannot create new file")); @@ -1532,14 +1486,20 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc, goto nonew_unlink; } - /* Set the mode of the new file to the same values the original file - has. */ if (fd != -1 - && (fchmod (newfd, st.st_mode & ALLPERMS) != 0 + && ( +#if HAVE_DECL_FCHMOD + /* Set the mode of the new file to the same values the original file + has. */ + fchmod (newfd, st.st_mode & 07777) != 0 || +#endif + ( +#if HAVE_DECL_FCHOWN /* Never complain about fchown failing. */ - || (({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }), - close (newfd) != 0) - || (newfd = -1, rename (tmpfname, arfname) != 0))) + ({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }), +#endif + close (newfd) != 0) || (newfd = -1, close(fd) != 0) || + (fd = -1, unlink (arfname), rename (tmpfname, arfname) != 0))) goto nonew_unlink; errout: |