| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: arch.c,v 1.75 2020/07/26 20:21:31 rillig Exp $ */ | | 1 | /* $NetBSD: arch.c,v 1.76 2020/07/27 19:06:45 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | | 4 | * Copyright (c) 1988, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -59,34 +59,34 @@ | | | @@ -59,34 +59,34 @@ |
59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
68 | * SUCH DAMAGE. | | 68 | * SUCH DAMAGE. |
69 | */ | | 69 | */ |
70 | | | 70 | |
71 | #ifndef MAKE_NATIVE | | 71 | #ifndef MAKE_NATIVE |
72 | static char rcsid[] = "$NetBSD: arch.c,v 1.75 2020/07/26 20:21:31 rillig Exp $"; | | 72 | static char rcsid[] = "$NetBSD: arch.c,v 1.76 2020/07/27 19:06:45 rillig Exp $"; |
73 | #else | | 73 | #else |
74 | #include <sys/cdefs.h> | | 74 | #include <sys/cdefs.h> |
75 | #ifndef lint | | 75 | #ifndef lint |
76 | #if 0 | | 76 | #if 0 |
77 | static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94"; | | 77 | static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94"; |
78 | #else | | 78 | #else |
79 | __RCSID("$NetBSD: arch.c,v 1.75 2020/07/26 20:21:31 rillig Exp $"); | | 79 | __RCSID("$NetBSD: arch.c,v 1.76 2020/07/27 19:06:45 rillig Exp $"); |
80 | #endif | | 80 | #endif |
81 | #endif /* not lint */ | | 81 | #endif /* not lint */ |
82 | #endif | | 82 | #endif |
83 | | | 83 | |
84 | /*- | | 84 | /*- |
85 | * arch.c -- | | 85 | * arch.c -- |
86 | * Functions to manipulate libraries, archives and their members. | | 86 | * Functions to manipulate libraries, archives and their members. |
87 | * | | 87 | * |
88 | * Once again, cacheing/hashing comes into play in the manipulation | | 88 | * Once again, cacheing/hashing comes into play in the manipulation |
89 | * of archives. The first time an archive is referenced, all of its members' | | 89 | * of archives. The first time an archive is referenced, all of its members' |
90 | * headers are read and hashed and the archive closed again. All hashed | | 90 | * headers are read and hashed and the archive closed again. All hashed |
91 | * archives are kept on a list which is searched each time an archive member | | 91 | * archives are kept on a list which is searched each time an archive member |
92 | * is referenced. | | 92 | * is referenced. |
| @@ -158,28 +158,29 @@ static Lst archives; /* Lst of archi | | | @@ -158,28 +158,29 @@ static Lst archives; /* Lst of archi |
158 | | | 158 | |
159 | typedef struct Arch { | | 159 | typedef struct Arch { |
160 | char *name; /* Name of archive */ | | 160 | char *name; /* Name of archive */ |
161 | Hash_Table members; /* All the members of the archive described | | 161 | Hash_Table members; /* All the members of the archive described |
162 | * by <name, struct ar_hdr *> key/value pairs */ | | 162 | * by <name, struct ar_hdr *> key/value pairs */ |
163 | char *fnametab; /* Extended name table strings */ | | 163 | char *fnametab; /* Extended name table strings */ |
164 | size_t fnamesize; /* Size of the string table */ | | 164 | size_t fnamesize; /* Size of the string table */ |
165 | } Arch; | | 165 | } Arch; |
166 | | | 166 | |
167 | static int ArchFindArchive(const void *, const void *); | | 167 | static int ArchFindArchive(const void *, const void *); |
168 | #ifdef CLEANUP | | 168 | #ifdef CLEANUP |
169 | static void ArchFree(void *); | | 169 | static void ArchFree(void *); |
170 | #endif | | 170 | #endif |
171 | static struct ar_hdr *ArchStatMember(char *, char *, Boolean); | | 171 | static struct ar_hdr *ArchStatMember(const char *, const char *, Boolean); |
172 | static FILE *ArchFindMember(char *, char *, struct ar_hdr *, const char *); | | 172 | static FILE *ArchFindMember(const char *, const char *, |
| | | 173 | struct ar_hdr *, const char *); |
173 | #if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) | | 174 | #if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) |
174 | #define SVR4ARCHIVES | | 175 | #define SVR4ARCHIVES |
175 | static int ArchSVR4Entry(Arch *, char *, size_t, FILE *); | | 176 | static int ArchSVR4Entry(Arch *, char *, size_t, FILE *); |
176 | #endif | | 177 | #endif |
177 | | | 178 | |
178 | #ifdef CLEANUP | | 179 | #ifdef CLEANUP |
179 | /*- | | 180 | /*- |
180 | *----------------------------------------------------------------------- | | 181 | *----------------------------------------------------------------------- |
181 | * ArchFree -- | | 182 | * ArchFree -- |
182 | * Free memory used by an archive | | 183 | * Free memory used by an archive |
183 | * | | 184 | * |
184 | * Results: | | 185 | * Results: |
185 | * None. | | 186 | * None. |
| @@ -513,49 +514,48 @@ ArchFindArchive(const void *ar, const vo | | | @@ -513,49 +514,48 @@ ArchFindArchive(const void *ar, const vo |
513 | * | | 514 | * |
514 | * Results: | | 515 | * Results: |
515 | * A pointer to the current struct ar_hdr structure for the member. Note | | 516 | * A pointer to the current struct ar_hdr structure for the member. Note |
516 | * That no position is returned, so this is not useful for touching | | 517 | * That no position is returned, so this is not useful for touching |
517 | * archive members. This is mostly because we have no assurances that | | 518 | * archive members. This is mostly because we have no assurances that |
518 | * The archive will remain constant after we read all the headers, so | | 519 | * The archive will remain constant after we read all the headers, so |
519 | * there's not much point in remembering the position... | | 520 | * there's not much point in remembering the position... |
520 | * | | 521 | * |
521 | * Side Effects: | | 522 | * Side Effects: |
522 | * | | 523 | * |
523 | *----------------------------------------------------------------------- | | 524 | *----------------------------------------------------------------------- |
524 | */ | | 525 | */ |
525 | static struct ar_hdr * | | 526 | static struct ar_hdr * |
526 | ArchStatMember(char *archive, char *member, Boolean hash) | | 527 | ArchStatMember(const char *archive, const char *member, Boolean hash) |
527 | { | | 528 | { |
528 | #define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1) | | 529 | #define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1) |
529 | FILE * arch; /* Stream to archive */ | | 530 | FILE * arch; /* Stream to archive */ |
530 | int size; /* Size of archive member */ | | 531 | int size; /* Size of archive member */ |
531 | char *cp; /* Useful character pointer */ | | | |
532 | char magic[SARMAG]; | | 532 | char magic[SARMAG]; |
533 | LstNode ln; /* Lst member containing archive descriptor */ | | 533 | LstNode ln; /* Lst member containing archive descriptor */ |
534 | Arch *ar; /* Archive descriptor */ | | 534 | Arch *ar; /* Archive descriptor */ |
535 | Hash_Entry *he; /* Entry containing member's description */ | | 535 | Hash_Entry *he; /* Entry containing member's description */ |
536 | struct ar_hdr arh; /* archive-member header for reading archive */ | | 536 | struct ar_hdr arh; /* archive-member header for reading archive */ |
537 | char memName[MAXPATHLEN+1]; | | 537 | char memName[MAXPATHLEN+1]; |
538 | /* Current member name while hashing. */ | | 538 | /* Current member name while hashing. */ |
539 | | | 539 | |
540 | /* | | 540 | /* |
541 | * Because of space constraints and similar things, files are archived | | 541 | * Because of space constraints and similar things, files are archived |
542 | * using their final path components, not the entire thing, so we need | | 542 | * using their final path components, not the entire thing, so we need |
543 | * to point 'member' to the final component, if there is one, to make | | 543 | * to point 'member' to the final component, if there is one, to make |
544 | * the comparisons easier... | | 544 | * the comparisons easier... |
545 | */ | | 545 | */ |
546 | cp = strrchr(member, '/'); | | 546 | const char *base = strrchr(member, '/'); |
547 | if (cp != NULL) { | | 547 | if (base != NULL) { |
548 | member = cp + 1; | | 548 | member = base + 1; |
549 | } | | 549 | } |
550 | | | 550 | |
551 | ln = Lst_Find(archives, archive, ArchFindArchive); | | 551 | ln = Lst_Find(archives, archive, ArchFindArchive); |
552 | if (ln != NULL) { | | 552 | if (ln != NULL) { |
553 | ar = (Arch *)Lst_Datum(ln); | | 553 | ar = (Arch *)Lst_Datum(ln); |
554 | | | 554 | |
555 | he = Hash_FindEntry(&ar->members, member); | | 555 | he = Hash_FindEntry(&ar->members, member); |
556 | | | 556 | |
557 | if (he != NULL) { | | 557 | if (he != NULL) { |
558 | return (struct ar_hdr *)Hash_GetValue(he); | | 558 | return (struct ar_hdr *)Hash_GetValue(he); |
559 | } else { | | 559 | } else { |
560 | /* Try truncated name */ | | 560 | /* Try truncated name */ |
561 | char copy[AR_MAX_NAME_LEN+1]; | | 561 | char copy[AR_MAX_NAME_LEN+1]; |
| @@ -626,51 +626,52 @@ ArchStatMember(char *archive, char *memb | | | @@ -626,51 +626,52 @@ ArchStatMember(char *archive, char *memb |
626 | */ | | 626 | */ |
627 | goto badarch; | | 627 | goto badarch; |
628 | } else { | | 628 | } else { |
629 | /* | | 629 | /* |
630 | * We need to advance the stream's pointer to the start of the | | 630 | * We need to advance the stream's pointer to the start of the |
631 | * next header. Files are padded with newlines to an even-byte | | 631 | * next header. Files are padded with newlines to an even-byte |
632 | * boundary, so we need to extract the size of the file from the | | 632 | * boundary, so we need to extract the size of the file from the |
633 | * 'size' field of the header and round it up during the seek. | | 633 | * 'size' field of the header and round it up during the seek. |
634 | */ | | 634 | */ |
635 | arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; | | 635 | arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; |
636 | size = (int)strtol(arh.ar_size, NULL, 10); | | 636 | size = (int)strtol(arh.ar_size, NULL, 10); |
637 | | | 637 | |
638 | memcpy(memName, arh.ar_name, sizeof(arh.ar_name)); | | 638 | memcpy(memName, arh.ar_name, sizeof(arh.ar_name)); |
639 | for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { | | 639 | char *nameend = memName + AR_MAX_NAME_LEN; |
640 | continue; | | 640 | while (*nameend == ' ') { |
| | | 641 | nameend--; |
641 | } | | 642 | } |
642 | cp[1] = '\0'; | | 643 | nameend[1] = '\0'; |
643 | | | 644 | |
644 | #ifdef SVR4ARCHIVES | | 645 | #ifdef SVR4ARCHIVES |
645 | /* | | 646 | /* |
646 | * svr4 names are slash terminated. Also svr4 extended AR format. | | 647 | * svr4 names are slash terminated. Also svr4 extended AR format. |
647 | */ | | 648 | */ |
648 | if (memName[0] == '/') { | | 649 | if (memName[0] == '/') { |
649 | /* | | 650 | /* |
650 | * svr4 magic mode; handle it | | 651 | * svr4 magic mode; handle it |
651 | */ | | 652 | */ |
652 | switch (ArchSVR4Entry(ar, memName, size, arch)) { | | 653 | switch (ArchSVR4Entry(ar, memName, size, arch)) { |
653 | case -1: /* Invalid data */ | | 654 | case -1: /* Invalid data */ |
654 | goto badarch; | | 655 | goto badarch; |
655 | case 0: /* List of files entry */ | | 656 | case 0: /* List of files entry */ |
656 | continue; | | 657 | continue; |
657 | default: /* Got the entry */ | | 658 | default: /* Got the entry */ |
658 | break; | | 659 | break; |
659 | } | | 660 | } |
660 | } | | 661 | } |
661 | else { | | 662 | else { |
662 | if (cp[0] == '/') | | 663 | if (nameend[0] == '/') |
663 | cp[0] = '\0'; | | 664 | nameend[0] = '\0'; |
664 | } | | 665 | } |
665 | #endif | | 666 | #endif |
666 | | | 667 | |
667 | #ifdef AR_EFMT1 | | 668 | #ifdef AR_EFMT1 |
668 | /* | | 669 | /* |
669 | * BSD 4.4 extended AR format: #1/<namelen>, with name as the | | 670 | * BSD 4.4 extended AR format: #1/<namelen>, with name as the |
670 | * first <namelen> bytes of the file | | 671 | * first <namelen> bytes of the file |
671 | */ | | 672 | */ |
672 | if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && | | 673 | if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && |
673 | isdigit((unsigned char)memName[sizeof(AR_EFMT1) - 1])) { | | 674 | isdigit((unsigned char)memName[sizeof(AR_EFMT1) - 1])) { |
674 | | | 675 | |
675 | unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); | | 676 | unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); |
676 | | | 677 | |
| @@ -836,59 +837,58 @@ ArchSVR4Entry(Arch *ar, char *name, size | | | @@ -836,59 +837,58 @@ ArchSVR4Entry(Arch *ar, char *name, size |
836 | * mode The mode for opening the stream | | 837 | * mode The mode for opening the stream |
837 | * | | 838 | * |
838 | * Results: | | 839 | * Results: |
839 | * An FILE *, opened for reading and writing, positioned at the | | 840 | * An FILE *, opened for reading and writing, positioned at the |
840 | * start of the member's struct ar_hdr, or NULL if the member was | | 841 | * start of the member's struct ar_hdr, or NULL if the member was |
841 | * nonexistent. The current struct ar_hdr for member. | | 842 | * nonexistent. The current struct ar_hdr for member. |
842 | * | | 843 | * |
843 | * Side Effects: | | 844 | * Side Effects: |
844 | * The passed struct ar_hdr structure is filled in. | | 845 | * The passed struct ar_hdr structure is filled in. |
845 | * | | 846 | * |
846 | *----------------------------------------------------------------------- | | 847 | *----------------------------------------------------------------------- |
847 | */ | | 848 | */ |
848 | static FILE * | | 849 | static FILE * |
849 | ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, | | 850 | ArchFindMember(const char *archive, const char *member, struct ar_hdr *arhPtr, |
850 | const char *mode) | | 851 | const char *mode) |
851 | { | | 852 | { |
852 | FILE * arch; /* Stream to archive */ | | 853 | FILE * arch; /* Stream to archive */ |
853 | int size; /* Size of archive member */ | | 854 | int size; /* Size of archive member */ |
854 | char *cp; /* Useful character pointer */ | | | |
855 | char magic[SARMAG]; | | 855 | char magic[SARMAG]; |
856 | size_t len, tlen; | | 856 | size_t len, tlen; |
857 | | | 857 | |
858 | arch = fopen(archive, mode); | | 858 | arch = fopen(archive, mode); |
859 | if (arch == NULL) { | | 859 | if (arch == NULL) { |
860 | return NULL; | | 860 | return NULL; |
861 | } | | 861 | } |
862 | | | 862 | |
863 | /* | | 863 | /* |
864 | * We use the ARMAG string to make sure this is an archive we | | 864 | * We use the ARMAG string to make sure this is an archive we |
865 | * can handle... | | 865 | * can handle... |
866 | */ | | 866 | */ |
867 | if ((fread(magic, SARMAG, 1, arch) != 1) || | | 867 | if ((fread(magic, SARMAG, 1, arch) != 1) || |
868 | (strncmp(magic, ARMAG, SARMAG) != 0)) { | | 868 | (strncmp(magic, ARMAG, SARMAG) != 0)) { |
869 | fclose(arch); | | 869 | fclose(arch); |
870 | return NULL; | | 870 | return NULL; |
871 | } | | 871 | } |
872 | | | 872 | |
873 | /* | | 873 | /* |
874 | * Because of space constraints and similar things, files are archived | | 874 | * Because of space constraints and similar things, files are archived |
875 | * using their final path components, not the entire thing, so we need | | 875 | * using their final path components, not the entire thing, so we need |
876 | * to point 'member' to the final component, if there is one, to make | | 876 | * to point 'member' to the final component, if there is one, to make |
877 | * the comparisons easier... | | 877 | * the comparisons easier... |
878 | */ | | 878 | */ |
879 | cp = strrchr(member, '/'); | | 879 | const char *base = strrchr(member, '/'); |
880 | if (cp != NULL) { | | 880 | if (base != NULL) { |
881 | member = cp + 1; | | 881 | member = base + 1; |
882 | } | | 882 | } |
883 | len = tlen = strlen(member); | | 883 | len = tlen = strlen(member); |
884 | if (len > sizeof(arhPtr->ar_name)) { | | 884 | if (len > sizeof(arhPtr->ar_name)) { |
885 | tlen = sizeof(arhPtr->ar_name); | | 885 | tlen = sizeof(arhPtr->ar_name); |
886 | } | | 886 | } |
887 | | | 887 | |
888 | while (fread((char *)arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) { | | 888 | while (fread((char *)arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) { |
889 | if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof(arhPtr->ar_fmag) ) != 0) { | | 889 | if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof(arhPtr->ar_fmag) ) != 0) { |
890 | /* | | 890 | /* |
891 | * The header is bogus, so the archive is bad | | 891 | * The header is bogus, so the archive is bad |
892 | * and there's no way we can recover... | | 892 | * and there's no way we can recover... |
893 | */ | | 893 | */ |
894 | fclose(arch); | | 894 | fclose(arch); |