3 * Copyright (c) 1999 by Aaron R. Crane.
4 * Permission is granted to use, distribute, or modify this source,
5 * provided that this copyright notice remains intact.
8 * Copyright (c) 2014 by David I. Bell
9 * Permission is granted to use, distribute, or modify this source,
10 * provided that this copyright notice remains intact.
12 * The "ar" built-in command.
13 * This allows extraction and listing of ar files.
17 #include <sys/types.h>
31 * Structure to hold information about the archive file.
35 int fd; /* file reading archive from */
36 BOOL eof; /* end of file has been seen */
37 BOOL rescan; /* rescan the header just read */
38 char * nameTable; /* long name table */
41 * Information about the current file read from the archive.
42 * This is extracted from the latest member header read.
44 char * name; /* current file name */
45 time_t date; /* date of file */
46 uid_t uid; /* user id */
47 gid_t gid; /* group id */
48 mode_t mode; /* file protection */
49 off_t size; /* file size */
50 int pad; /* padding to next header */
57 static void initArchive(Archive * arch);
58 static BOOL openArchive(const char * name, Archive * arch);
59 static void closeArchive(Archive * arch);
60 static BOOL readSpecialMember(Archive * arch);
61 static BOOL readNormalMember(Archive * arch);
62 static BOOL readMember(Archive * arch, struct ar_hdr * hdr);
63 static BOOL skipMember(const Archive * arch);
64 static BOOL skipPadding(int fd, int pad);
65 static BOOL writeFile(const Archive * arch, int outfd);
66 static int createFile(const Archive * arch);
67 static BOOL canonicalize(Archive * arch, const struct ar_hdr * hdr);
68 static void listMember(const Archive * arch);
69 static int shortNameMatches44BSD(const char * name);
70 static int shortNameMatchesSysV(const char * name);
72 static BOOL wantMember(const Archive * arch, int n_names,
75 static BOOL getNumber(const char * s, unsigned base, int max_digits,
80 do_ar(int argc, const char ** argv)
83 const char * archiveName;
99 fprintf(stderr, "Too few arguments for ar\n");
105 * Get the option string and archive file name.
108 archiveName = argv[2];
111 * Advance the arguments to the list of file names (if any).
117 * Parse the option characters.
119 for (; *options; options++)
139 case 'd': case 'm': case 'q': case 'r':
140 fprintf(stderr, "Writing ar files is not supported\n");
145 fprintf(stderr, "Unknown ar flag: %c\n", *options);
151 if (doExtract + doTable + doPrint != 1)
154 "Exactly one of 'x', 'p' or 't' must be specified\n");
160 * Open the archive file.
164 if (!openArchive(archiveName, &arch))
168 * Read the first special member of the archive.
170 if (!readSpecialMember(&arch))
174 * Read all of the normal members of the archive.
176 while (readNormalMember(&arch))
179 * If this file is not wanted then skip it.
181 if (!wantMember(&arch, argc, argv))
183 if (!skipMember(&arch))
190 * This file is wanted.
199 if (!skipMember(&arch))
207 * The verbose format makes me gag,
208 * but 4.4BSD, GNU and even V7 all
209 * have the same lossage.
211 printf("\n<%s>\n\n", arch.name);
215 if (!writeFile(&arch, STDOUT))
224 printf("x - %s\n", arch.name);
226 outfd = createFile(&arch);
231 success = writeFile(&arch, outfd);
233 if (close(outfd) == -1)
235 fprintf(stderr, "Can't close %s: %s\n",
236 arch.name, strerror(errno));
249 fprintf(stderr, "Oops -- I don't know what to do\n");
262 * Open the file for writing for the specified archive structure,
263 * setting its mode and owner if possible. Returns the file handle
264 * of the opened file, or -1 on an error.
267 createFile(const Archive * arch)
271 fd = open(arch->name, O_WRONLY | O_CREAT | O_TRUNC, arch->mode);
275 fprintf(stderr, "Can't create \"%s\": %s\n",
276 arch->name, strerror(errno));
282 * Don't worry if these fail. We have to do the fchmod() despite
283 * specifying the mode in the open() call, because that mode is
284 * munged by the umask.
286 checkStatus("fchmod", fchmod(fd, arch->mode));
287 checkStatus("fchown", fchown(fd, arch->uid, arch->gid));
294 * Return whether the current archive member is wanted.
295 * This means that the file name is contained in the specified list of
296 * file names, or else that the specified list of file names is empty.
299 wantMember(const Archive * arch, int n_names, const char ** name)
304 * If there are no names then all archive members are wanted.
310 * See if the member file name is contained in the list.
312 for (i = 0; i < n_names; i++)
314 if (strcmp(arch->name, name[i]) == 0)
323 * Parse a number from the specified string in the specified base.
324 * The number is terminated by a null, space, or the specified number
325 * of digits. The number is returned through the supplied pointer.
326 * Only non-negatives numbers are parsed. Returns TRUE on success.
329 getNumber(const char * s, unsigned base, int max_digits, unsigned long * ul)
333 unsigned long cutoff;
334 unsigned long cutlim;
336 if (base < 2 || base > 10 || s == 0 || *s == 0 || ul == 0)
339 cutoff = ULONG_MAX / (unsigned long) base;
340 cutlim = ULONG_MAX % (unsigned long) base;
343 endp = (max_digits >= 0) ? s + max_digits : 0;
345 for (p = s; endp ? p < endp : 1; p++)
349 if (*p == 0 || *p == ' ')
350 break; /* end of string */
353 return FALSE; /* non-digit */
358 return FALSE; /* digit outside range for base */
360 if (*ul > cutoff || (*ul == cutoff && d > cutlim))
361 return FALSE; /* overflow */
368 return FALSE; /* nothing was converted */
371 return FALSE; /* trailing garbage */
378 * Initialise the specified Archive structure for use.
381 initArchive(Archive * arch)
387 arch->rescan = FALSE;
392 * Open the specified archive file name and read the header from it.
393 * The file handle is saved in the Archive structure for further use.
394 * Returns TRUE on success.
397 openArchive(const char * name, Archive * arch)
399 unsigned char buf[SARMAG];
402 arch->fd = open(name, O_RDONLY);
406 fprintf(stderr, "Can't open archive file %s: %s\n",
407 name, strerror(errno));
412 cc = read(arch->fd, buf, SARMAG);
416 fprintf(stderr, "Error reading archive header: %s\n",
424 fprintf(stderr, "Short read of archive header\n");
429 if (memcmp(buf, ARMAG, SARMAG))
431 fprintf(stderr, "Invalid archive header\n");
440 * Here on an error to clean up.
443 (void) close(arch->fd);
451 * Close the archive file.
454 closeArchive(Archive * arch)
459 free(arch->nameTable);
463 (void) close(arch->fd);
470 * Read an archive member header into the specified structure.
471 * Returns TRUE on success. On failure, the eof flag is set if
472 * the end of file had been reached.
475 readMember(Archive * arch, struct ar_hdr * hdr)
479 cc = read(arch->fd, hdr, sizeof(*hdr));
483 fprintf(stderr, "Error reading member header: %s\n",
496 if (cc != sizeof(*hdr))
498 fprintf(stderr, "Short read of member header\n");
503 if (memcmp(hdr->ar_fmag, ARFMAG, sizeof(hdr->ar_fmag)))
505 fprintf(stderr, "Invalid member header\n");
515 * Check the member file name and see if it matches the 4.4 BSD
516 * syntax for long file names. If so, return the number of characters
517 * of the actual long file name. Returns -1 on an error.
520 shortNameMatches44BSD(const char * name)
525 if (strncmp(name, "#1/", 3) != 0)
528 if (!isDecimal(name[3]))
531 for (p = name + 4; *p; p++)
543 if (!getNumber(name + 3, 10, -1, &ul))
546 if (ul == 0) /* broken archive */
554 * Check the member file name and see if it matches the SYS V syntax
555 * for long file names. If so, return the number of characters of the
556 * actual long file name. Returns -1 on an error.
559 shortNameMatchesSysV(const char * name)
568 if (!isDecimal(name[1]))
571 for (p = name + 2; *p; p++)
583 if (!getNumber(name + 1, 10, -1, &ul))
590 #define MEMB_NAME_ALLOC(n) \
593 arch->name = malloc(n); \
596 fprintf(stderr, "Out of memory\n"); \
603 * Examine the archive structure that was read and fill in the
604 * current member data with the extracted information. This handles
605 * various types of archive headers. This can read data from the
606 * archive file to obtain a long file name. Returns TRUE on success.
609 canonicalize(Archive * arch, const struct ar_hdr * hdr)
611 char buf[sizeof(hdr->ar_name) + 1];
614 unsigned long bsd_len;
621 strncpy(buf, hdr->ar_name, sizeof(hdr->ar_name));
622 buf[sizeof(hdr->ar_name)] = 0;
625 * 1. If shortname matches "^#1/(\d+) *$", then it's a 4.4BSD
626 * longname. Read a longname of $1 bytes from ARCH->fd, or
627 * return FALSE if impossible.
629 if ((n = shortNameMatches44BSD(buf)) != -1)
631 /* N is the length of the longname */
636 MEMB_NAME_ALLOC(n + 1);
638 cc = read(arch->fd, arch->name, n);
642 fprintf(stderr, "Error reading longname: %s\n",
650 fprintf(stderr, "Unexpected end of file in longname\n");
659 * 2. Otherwise, if shortname matches "^/(\d+) *$", then it's a SysV
660 * longname. Get the longname from the nameTable, or return FALSE
663 else if ((n = shortNameMatchesSysV(buf)) != -1)
666 * N is the index of the longname
668 const char * longname;
672 if (n >= strlen(arch->nameTable))
674 fprintf(stderr, "Longname index too large\n");
679 longname = arch->nameTable + n;
681 p = strchr(longname, '/');
685 fprintf(stderr, "Bad longname index\n");
692 fprintf(stderr, "Malformed longname table\n");
698 MEMB_NAME_ALLOC(len + 1);
699 strncpy(arch->name, longname, len);
700 arch->name[len] = '\0';
704 * 3. Otherwise, it's just a shortname. If the shortname contains a
705 * slash, then the name terminates before the slash; otherwise,
706 * the name terminates at the first space, or at the end of the
707 * field if there is none. */
713 p = strchr(buf, '/');
716 p = strchr(buf, ' ');
721 len = sizeof(hdr->ar_name);
723 MEMB_NAME_ALLOC(len + 1);
724 strncpy(arch->name, buf, len);
729 * 4. Parse the remaining fields of the header. Return FALSE if any
730 * are missing or ill-formed.
732 #define FIELD(AFIELD, MFIELD, base) \
733 if (!getNumber(hdr->AFIELD, base, sizeof(hdr->AFIELD), &ul)) \
735 fprintf(stderr, "Malformed archive member header\n"); \
740 FIELD(ar_date, date, 10);
741 FIELD(ar_uid, uid, 10);
742 FIELD(ar_gid, gid, 10);
743 FIELD(ar_mode, mode, 8);
744 FIELD(ar_size, size, 10);
748 * 4a. Decide whether a pad byte will be present.u
750 * The 4.4BSD format is really broken and needs a whole pile of
751 * cruft to deal with it. There are several cases:
753 * 1. Even namelen, even memberlen: no pad.
754 * 2. Even namelen, odd memberlen: pad. Just like SysV.
755 * 3. Odd namelen, even memberlen: pad. Cruft.
756 * 4. Odd namelen, odd memberlen: no pad. Cruft.
758 * Essentially, whenever the namelen is odd, the naive determination
759 * of whether a pad is needed is reversed.
762 arch->pad = (arch->size % 2) ? 1 : 0;
765 arch->size -= bsd_len;
766 arch->pad = (arch->size % 2) ? 1 : 0;
769 arch->pad = !arch->pad;
773 * 5. Everything was successful.
779 * 5a. Error exit -- free memory.
790 * Skip the padding character if required to position to the
791 * beginning of the next member header. This is done if the
792 * padding value is nonzero. Returns TRUE on success.
795 skipPadding(int fd, int pad)
799 if (lseek(fd, 1, SEEK_CUR) == -1)
801 fprintf(stderr, "Can't skip pad byte: %s\n",
813 * Read the first member of the archive file and check whether it
814 * is a special one, and if so, handle it. If the first member is
815 * a normal archive member, then set up to rescan it for the next
816 * readNormalMember call. Returns TRUE on success.
819 readSpecialMember(Archive * arch)
824 * 1. Read a header H. Fail if impossible.
826 if (!readMember(arch, &hdr))
830 * 2. If H is a symbol table, ditch it.
831 * Fail if impossible.
833 if ((strncmp(hdr.ar_name, "/ ", 2) == 0) ||
834 (strncmp(hdr.ar_name, "__.SYMTAB ",
835 sizeof(hdr.ar_name)) == 0))
837 if (!canonicalize(arch, &hdr))
840 return skipMember(arch);
844 * 3. If H is a SysV longname table, read it into ARCH.
846 if (strncmp(hdr.ar_name, "//", 2) == 0)
851 if (!getNumber(hdr.ar_size, 10, sizeof(hdr.ar_size), &len))
853 fprintf(stderr, "Invalid name-table size\n");
858 arch->nameTable = malloc(len + 1);
860 if (!arch->nameTable)
862 fprintf(stderr, "Out of memory\n");
867 cc = read(arch->fd, arch->nameTable, len);
871 fprintf(stderr, "Error reading name-table: %s\n",
877 if (cc != (ssize_t) len)
880 "Unexpected end of file in name-table\n");
885 arch->nameTable[len] = 0;
887 return skipPadding(arch->fd, len % 2);
891 * 4. We read a normal header.
892 * Canonicalize it, and mark it as needing rescanning.
896 return canonicalize(arch, &hdr);
901 * Read the next normal member of the archive file if possible.
902 * If the member is being rescanned, clear the rescan flag and
903 * return the header that was already read. Returns TRUE on
904 * success. On a failure, the eof flag will be set if end of
905 * file has been reached.
908 readNormalMember(Archive * arch)
913 * If we are rereading an old header then just clear the
914 * rescan flag and return success.
918 arch->rescan = FALSE;
924 * We need to read a new member header.
926 if (!readMember(arch, &hdr))
929 return canonicalize(arch, &hdr);
934 * Skip the current member of the archive so that we are positioned
935 * to tbe beginning of the next member's header (or end of file).
936 * Returns TRUE on success.
939 skipMember(const Archive * arch)
941 if (lseek(arch->fd, arch->size, SEEK_CUR) == -1)
943 fprintf(stderr, "Can't skip past archive member: %s\n",
949 return skipPadding(arch->fd, arch->pad);
954 * Copy all of the file data from the archive to the specified
955 * open file. Returns TRUE on success.
958 writeFile(const Archive * arch, int outfd)
969 cc = read(arch->fd, buf, MIN(n, sizeof(buf)));
973 fprintf(stderr, "Error reading archive member: %s\n",
981 fprintf(stderr, "Unexpected end of file\n");
986 if (fullWrite(outfd, buf, cc) < 0)
988 fprintf(stderr, "Write error: %s\n", strerror(errno));
996 if (!skipPadding(arch->fd, arch->pad))
1004 * Print one line listing the information about the specified archive member.
1007 listMember(const Archive * arch)
1009 printf("%s %6ld/%-6ld %8lu %s %s\n",
1010 modeString(arch->mode) + 1,
1013 (unsigned long) arch->size,
1014 timeString(arch->date),