]> err.no Git - sash/blob - cmd_ar.c
Stop stripping during build. Also thanks to Helmut Grohne. Closes: #852771
[sash] / cmd_ar.c
1 /*
2  * Original:
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.
6  *
7  * Modified:
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.
11  *
12  * The "ar" built-in command.
13  * This allows extraction and listing of ar files.
14  */
15
16 #include <ar.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <limits.h>
26
27 #include "sash.h"
28
29
30 /*
31  * Structure to hold information about the archive file.
32  */
33 typedef struct
34 {
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 */
39
40         /*
41          * Information about the current file read from the archive.
42          * This is extracted from the latest member header read.
43          */
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 */
51 } Archive;
52
53
54 /*
55  * Local procedures.
56  */
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);
71
72 static  BOOL    wantMember(const Archive * arch, int n_names,
73                         const char ** names);
74
75 static BOOL     getNumber(const char * s, unsigned base, int max_digits,
76                         unsigned long * ul);
77
78
79 int
80 do_ar(int argc, const char ** argv)
81 {
82         const char *    options;
83         const char *    archiveName;
84         BOOL            doExtract;
85         BOOL            doTable;
86         BOOL            doPrint;
87         BOOL            verbose;
88         int             r;
89         Archive         arch;
90
91         r = 0;
92         verbose = FALSE;
93         doExtract = FALSE;
94         doTable = FALSE;
95         doPrint = FALSE;
96
97         if (argc < 3)
98         {
99                 fprintf(stderr, "Too few arguments for ar\n");
100
101                 return 1;
102         }
103
104         /*
105          * Get the option string and archive file name.
106          */
107         options = argv[1];
108         archiveName = argv[2];
109
110         /*
111          * Advance the arguments to the list of file names (if any).
112          */
113         argc -= 3;
114         argv += 3;
115
116         /*
117          * Parse the option characters.
118          */
119         for (; *options; options++)
120         {
121                 switch (*options)
122                 {
123                 case 't':
124                         doTable = TRUE;
125                         break;
126
127                 case 'x':
128                         doExtract = TRUE;
129                         break;
130
131                 case 'p':
132                         doPrint = TRUE;
133                         break;
134
135                 case 'v':
136                         verbose = TRUE;
137                         break;
138
139                 case 'd': case 'm': case 'q': case 'r':
140                         fprintf(stderr, "Writing ar files is not supported\n");
141
142                         return 1;
143
144                 default:
145                         fprintf(stderr, "Unknown ar flag: %c\n", *options);
146
147                         return 1;
148                 }
149         }
150
151         if (doExtract + doTable + doPrint != 1)
152         {
153                 fprintf(stderr,
154                         "Exactly one of 'x', 'p' or 't' must be specified\n");
155
156                 return 1;
157         }
158
159         /*
160          * Open the archive file.
161          */
162         initArchive(&arch);
163
164         if (!openArchive(archiveName, &arch))
165                 return 1;
166
167         /*
168          * Read the first special member of the archive.
169          */
170         if (!readSpecialMember(&arch))
171                 return 1;
172
173         /*
174          * Read all of the normal members of the archive.
175          */
176         while (readNormalMember(&arch))
177         {
178                 /*
179                  * If this file is not wanted then skip it.
180                  */
181                 if (!wantMember(&arch, argc, argv))
182                 {
183                         if (!skipMember(&arch))
184                                 break;
185
186                         continue;
187                 }
188
189                 /*
190                  * This file is wanted.
191                  */
192                 if (doTable)
193                 {
194                         if (verbose)
195                                 listMember(&arch);
196                         else
197                                 puts(arch.name);
198
199                         if (!skipMember(&arch))
200                                 break;
201                 }
202                 else if (doPrint)
203                 {
204                         if (verbose)
205                         {
206                                 /*
207                                  * The verbose format makes me gag,
208                                  * but 4.4BSD, GNU and even V7 all
209                                  * have the same lossage.
210                                  */
211                                 printf("\n<%s>\n\n", arch.name);
212                                 fflush(stdout);
213                         }
214
215                         if (!writeFile(&arch, STDOUT))
216                                 break;
217                 }
218                 else if (doExtract)
219                 {
220                         int     outfd;
221                         BOOL    success;
222
223                         if (verbose)
224                                 printf("x - %s\n", arch.name);
225
226                         outfd = createFile(&arch);
227
228                         if (outfd == -1)
229                                 break;
230
231                         success = writeFile(&arch, outfd);
232
233                         if (close(outfd) == -1)
234                         {
235                                 fprintf(stderr, "Can't close %s: %s\n",
236                                         arch.name, strerror(errno));
237
238                                 break;
239                         }
240
241                         if (!success)
242                         {
243                                 r = 1;
244                                 break;
245                         }
246                 }
247                 else
248                 {
249                         fprintf(stderr, "Oops -- I don't know what to do\n");
250                         r = 1;
251                         break;
252                 }
253         }
254
255         closeArchive(&arch);
256
257         return r;
258 }
259
260
261 /*
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.
265  */
266 static int
267 createFile(const Archive * arch)
268 {
269         int     fd;
270
271         fd = open(arch->name, O_WRONLY | O_CREAT | O_TRUNC, arch->mode);
272
273         if (fd == -1)
274         {
275                 fprintf(stderr, "Can't create \"%s\": %s\n",
276                         arch->name, strerror(errno));
277
278                 return -1;
279         }
280
281         /*
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.
285          */
286         checkStatus("fchmod", fchmod(fd, arch->mode));
287         checkStatus("fchown", fchown(fd, arch->uid, arch->gid));
288
289         return fd;
290 }
291
292
293 /*
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.
297  */
298 static BOOL
299 wantMember(const Archive * arch, int n_names, const char ** name)
300 {
301         int     i;
302
303         /*
304          * If there are no names then all archive members are wanted.
305          */
306         if (n_names == 0)
307                 return TRUE;
308
309         /*
310          * See if the member file name is contained in the list.
311          */
312         for (i = 0; i < n_names; i++)
313         {
314                 if (strcmp(arch->name, name[i]) == 0)
315                         return TRUE;
316         }
317
318         return FALSE;
319 }
320
321
322 /*
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.
327  */
328 static BOOL
329 getNumber(const char * s, unsigned base, int max_digits, unsigned long * ul)
330 {
331         const char *    p;
332         const char *    endp;
333         unsigned long   cutoff;
334         unsigned long   cutlim;
335
336         if (base < 2 || base > 10  ||  s == 0 || *s == 0  ||  ul == 0)
337                 return FALSE;
338
339         cutoff = ULONG_MAX / (unsigned long) base;
340         cutlim = ULONG_MAX % (unsigned long) base;
341         *ul = 0;
342
343         endp = (max_digits >= 0) ? s + max_digits : 0;
344
345         for (p = s;  endp ? p < endp : 1;  p++)
346         {
347                 unsigned d;
348
349                 if (*p == 0 || *p == ' ')
350                         break;  /* end of string */
351
352                 if (!isDecimal(*p))
353                         return FALSE; /* non-digit */
354
355                 d = *p - '0';
356
357                 if (d >= base)
358                         return FALSE; /* digit outside range for base */
359
360                 if (*ul > cutoff || (*ul == cutoff && d > cutlim))
361                         return FALSE; /* overflow */
362
363                 *ul *= base;
364                 *ul += d;
365         }
366
367         if (p == s)
368                 return FALSE;   /* nothing was converted */
369
370         if (*p && *p != ' ')
371                 return FALSE;   /* trailing garbage */
372
373         return TRUE;
374 }
375
376
377 /*
378  * Initialise the specified Archive structure for use.
379  */
380 static void
381 initArchive(Archive * arch)
382 {
383         arch->fd = -1;
384         arch->name = 0;
385         arch->nameTable = 0;
386         arch->eof = FALSE;
387         arch->rescan = FALSE;
388 }
389
390
391 /*
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.
395  */
396 static BOOL
397 openArchive(const char * name, Archive * arch)
398 {
399         unsigned char   buf[SARMAG];
400         ssize_t         cc;
401
402         arch->fd = open(name, O_RDONLY);
403
404         if (arch->fd == -1)
405         {
406                 fprintf(stderr, "Can't open archive file %s: %s\n",
407                         name, strerror(errno));
408
409                 return FALSE;
410         }
411
412         cc = read(arch->fd, buf, SARMAG);
413
414         if (cc == -1)
415         {
416                 fprintf(stderr, "Error reading archive header: %s\n",
417                         strerror(errno));
418
419                 goto close_and_out;
420         } 
421
422         if (cc != SARMAG)
423         {
424                 fprintf(stderr, "Short read of archive header\n");
425
426                 goto close_and_out;
427         }
428
429         if (memcmp(buf, ARMAG, SARMAG))
430         {
431                 fprintf(stderr, "Invalid archive header\n");
432
433                 goto close_and_out;
434         }
435
436         return TRUE;
437
438
439         /*
440          * Here on an error to clean up.
441          */
442 close_and_out:
443         (void) close(arch->fd);
444         arch->fd = -1;
445
446         return FALSE;
447 }
448
449
450 /*
451  * Close the archive file.
452  */
453 static void
454 closeArchive(Archive * arch)
455 {
456         free(arch->name);
457         arch->name = 0;
458
459         free(arch->nameTable);
460         arch->nameTable = 0;
461
462         if (arch->fd >= 0)
463                 (void) close(arch->fd);
464
465         arch->fd = -1;
466 }
467
468
469 /*
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.
473  */
474 static BOOL
475 readMember(Archive * arch, struct ar_hdr * hdr)
476 {
477         ssize_t cc;
478
479         cc = read(arch->fd, hdr, sizeof(*hdr));
480
481         if (cc < 0)
482         {
483                 fprintf(stderr, "Error reading member header: %s\n",
484                         strerror(errno));
485
486                 return FALSE;
487         }
488
489         if (cc == 0)
490         {
491                 arch->eof = TRUE;
492
493                 return FALSE;
494         }
495
496         if (cc != sizeof(*hdr))
497         {
498                 fprintf(stderr, "Short read of member header\n");
499
500                 return FALSE;
501         }
502
503         if (memcmp(hdr->ar_fmag, ARFMAG, sizeof(hdr->ar_fmag)))
504         {
505                 fprintf(stderr, "Invalid member header\n");
506
507                 return FALSE;
508         }
509
510         return TRUE;
511 }
512
513
514 /*
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.
518  */
519 static int
520 shortNameMatches44BSD(const char * name)
521 {
522         const char *    p;
523         unsigned long   ul;
524
525         if (strncmp(name, "#1/", 3) != 0)
526                 return -1;
527
528         if (!isDecimal(name[3]))
529                 return -1;
530
531         for (p = name + 4;  *p;  p++)
532         {
533                 if (!isDecimal(*p))
534                         break;
535         }
536
537         while (*p)
538         {
539                 if (*p++ != ' ')
540                         return -1;
541         }
542
543         if (!getNumber(name + 3, 10, -1, &ul))
544                 return -1;
545
546         if (ul == 0)            /* broken archive */
547                 return -1;
548
549         return ul;
550 }
551
552
553 /*
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.
557  */
558 static int
559 shortNameMatchesSysV(const char * name)
560 {
561         const char *    p;
562         unsigned long   ul;
563
564         /* "^/(\d+) *$" */
565         if (name[0] != '/')
566                 return -1;
567
568         if (!isDecimal(name[1]))
569                 return -1;
570
571         for (p = name + 2;  *p;  p++)
572         {
573                 if (!isDecimal(*p))
574                         break;
575         }
576
577         while (*p)
578         {
579                 if (*p++ != ' ')
580                         return -1;
581         }
582
583         if (!getNumber(name + 1, 10, -1, &ul))
584                 return -1;
585
586         return ul;
587 }
588
589
590 #define MEMB_NAME_ALLOC(n)                                      \
591         do                                                      \
592         {                                                       \
593                 arch->name = malloc(n);                         \
594                 if (!arch->name)                                \
595                 {                                               \
596                         fprintf(stderr, "Out of memory\n");     \
597                         return FALSE;                           \
598                 }                                               \
599         } while (0);
600
601
602 /*
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.
607  */
608 static BOOL
609 canonicalize(Archive * arch, const struct ar_hdr * hdr)
610 {
611         char            buf[sizeof(hdr->ar_name) + 1];
612         int             n;
613         unsigned long   ul;
614         unsigned long   bsd_len;
615
616         bsd_len = 0;
617
618         free(arch->name);
619         arch->name = 0;
620
621         strncpy(buf, hdr->ar_name, sizeof(hdr->ar_name));
622         buf[sizeof(hdr->ar_name)] = 0;
623
624         /*
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.
628          */
629         if ((n = shortNameMatches44BSD(buf)) != -1)
630         {
631                 /* N is the length of the longname */
632                 ssize_t cc;
633
634                 bsd_len = n;
635
636                 MEMB_NAME_ALLOC(n + 1);
637
638                 cc = read(arch->fd, arch->name, n);
639
640                 if (cc == -1)
641                 {
642                         fprintf(stderr, "Error reading longname: %s\n",
643                                 strerror(errno));
644
645                         goto free_and_out;
646                 }
647
648                 if (cc != n)
649                 {
650                         fprintf(stderr, "Unexpected end of file in longname\n");
651
652                         goto free_and_out;
653                 }
654
655                 arch->name[n] = 0;
656         }
657
658         /*
659          * 2. Otherwise, if shortname matches "^/(\d+) *$", then it's a SysV
660          *    longname.  Get the longname from the nameTable, or return FALSE
661          *    if there is none.
662          */
663         else if ((n = shortNameMatchesSysV(buf)) != -1)
664         {
665                 /*
666                  * N is the index of the longname
667                  */
668                 const char *    longname;
669                 const char *    p;
670                 size_t          len;
671
672                 if (n >= strlen(arch->nameTable))
673                 {
674                         fprintf(stderr, "Longname index too large\n");
675
676                         return FALSE;
677                 }
678
679                 longname = arch->nameTable + n;
680
681                 p = strchr(longname, '/');
682
683                 if (!p)
684                 {
685                         fprintf(stderr, "Bad longname index\n");
686
687                         return FALSE;
688                 }
689
690                 if (p[1] != '\n')
691                 {
692                         fprintf(stderr, "Malformed longname table\n");
693
694                         return FALSE;
695                 }
696
697                 len = p - longname;
698                 MEMB_NAME_ALLOC(len + 1);
699                 strncpy(arch->name, longname, len);
700                 arch->name[len] = '\0';
701         }
702
703         /*
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. */
708         else
709         {
710                 const char *    p;
711                 size_t          len;
712
713                 p = strchr(buf, '/');
714
715                 if (!p)
716                         p = strchr(buf, ' ');
717
718                 if (p)
719                         len = p - buf;
720                 else
721                         len = sizeof(hdr->ar_name);
722
723                 MEMB_NAME_ALLOC(len + 1);
724                 strncpy(arch->name, buf, len);
725                 arch->name[len] = 0;
726         }
727
728         /*
729          * 4. Parse the remaining fields of the header.  Return FALSE if any
730          *    are missing or ill-formed.
731          */
732 #define FIELD(AFIELD, MFIELD, base)                                     \
733         if (!getNumber(hdr->AFIELD, base, sizeof(hdr->AFIELD), &ul))    \
734         {                                                               \
735                 fprintf(stderr, "Malformed archive member header\n");   \
736                 goto free_and_out;                                      \
737         }                                                               \
738         arch->MFIELD = ul;
739
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);
745 #undef FIELD
746
747         /*
748          * 4a. Decide whether a pad byte will be present.u
749          *
750          * The 4.4BSD format is really broken and needs a whole pile of
751          * cruft to deal with it.  There are several cases:
752          *
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.
757          *
758          * Essentially, whenever the namelen is odd, the naive determination
759          * of whether a pad is needed is reversed.
760          */
761         if (!bsd_len)
762                 arch->pad = (arch->size % 2) ? 1 : 0;
763         else
764         {
765                 arch->size -= bsd_len;
766                 arch->pad = (arch->size % 2) ? 1 : 0;
767
768                 if (bsd_len % 2)
769                         arch->pad = !arch->pad;
770         }
771
772         /*
773          * 5. Everything was successful.
774          */
775         return TRUE;
776
777
778         /*
779          * 5a. Error exit -- free memory.
780          */
781 free_and_out:
782         free(arch->name);
783         arch->name = 0;
784
785         return FALSE;
786 }
787
788
789 /*
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.
793  */
794 static BOOL
795 skipPadding(int fd, int pad)
796 {
797         if (pad)
798         {
799                 if (lseek(fd, 1, SEEK_CUR) == -1)
800                 {
801                         fprintf(stderr, "Can't skip pad byte: %s\n",
802                                 strerror(errno));
803
804                         return FALSE;
805                 }
806         }
807
808         return TRUE;
809 }
810
811
812 /*
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.
817  */
818 static BOOL
819 readSpecialMember(Archive * arch)
820 {
821         struct ar_hdr   hdr;
822
823         /*
824          * 1. Read a header H.  Fail if impossible.
825          */
826         if (!readMember(arch, &hdr))
827                 return FALSE;
828
829         /*
830          * 2. If H is a symbol table, ditch it.
831          * Fail if impossible.
832          */
833         if ((strncmp(hdr.ar_name, "/ ", 2) == 0) ||
834                 (strncmp(hdr.ar_name, "__.SYMTAB       ",
835                         sizeof(hdr.ar_name)) == 0))
836         {
837                 if (!canonicalize(arch, &hdr))
838                         return FALSE;
839
840                 return skipMember(arch);
841         }
842
843         /*
844          * 3. If H is a SysV longname table, read it into ARCH.
845          */
846         if (strncmp(hdr.ar_name, "//", 2) == 0)
847         {
848                 unsigned long   len;
849                 ssize_t         cc;
850
851                 if (!getNumber(hdr.ar_size, 10, sizeof(hdr.ar_size), &len))
852                 {
853                         fprintf(stderr, "Invalid name-table size\n");
854
855                         return FALSE;
856                 }
857
858                 arch->nameTable = malloc(len + 1);
859
860                 if (!arch->nameTable)
861                 {
862                         fprintf(stderr, "Out of memory\n");
863
864                         return FALSE;
865                 }
866
867                 cc = read(arch->fd, arch->nameTable, len);
868
869                 if (cc == -1)
870                 {
871                         fprintf(stderr, "Error reading name-table: %s\n",
872                                 strerror(errno));
873
874                         return FALSE;
875                 }
876
877                 if (cc != (ssize_t) len)
878                 {
879                         fprintf(stderr,
880                                 "Unexpected end of file in name-table\n");
881
882                         return FALSE;
883                 }
884
885                 arch->nameTable[len] = 0;
886
887                 return skipPadding(arch->fd, len % 2);
888         }
889
890         /*
891          * 4. We read a normal header.
892          * Canonicalize it, and mark it as needing rescanning.
893          */
894         arch->rescan = TRUE;
895
896         return canonicalize(arch, &hdr);
897 }
898
899
900 /*
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.
906  */
907 static BOOL
908 readNormalMember(Archive * arch)
909 {
910         struct ar_hdr   hdr;
911
912         /*
913          * If we are rereading an old header then just clear the
914          * rescan flag and return success.
915          */
916         if (arch->rescan)
917         {
918                 arch->rescan = FALSE;
919
920                 return TRUE;
921         }
922
923         /*
924          * We need to read a new member header.
925          */
926         if (!readMember(arch, &hdr))
927                 return FALSE;
928
929         return canonicalize(arch, &hdr);
930 }
931
932
933 /*
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.
937  */
938 static BOOL
939 skipMember(const Archive * arch)
940 {
941         if (lseek(arch->fd, arch->size, SEEK_CUR) == -1)
942         {
943                 fprintf(stderr, "Can't skip past archive member: %s\n",
944                         strerror(errno));
945
946                 return FALSE;
947         }
948
949         return skipPadding(arch->fd, arch->pad);
950 }
951
952
953 /*
954  * Copy all of the file data from the archive to the specified
955  * open file.  Returns TRUE on success.
956  */
957 static BOOL
958 writeFile(const Archive * arch, int outfd)
959 {
960         char    buf[BUF_SIZE];
961         off_t   n;
962
963         n = arch->size;
964
965         while (n > 0)
966         {
967                 ssize_t cc;
968
969                 cc = read(arch->fd, buf, MIN(n, sizeof(buf)));
970
971                 if (cc == -1)
972                 {
973                         fprintf(stderr, "Error reading archive member: %s\n",
974                                 strerror(errno));
975
976                         return FALSE;
977                 }
978
979                 if (cc == 0)
980                 {
981                         fprintf(stderr, "Unexpected end of file\n");
982
983                         return FALSE;
984                 }
985
986                 if (fullWrite(outfd, buf, cc) < 0)
987                 {
988                         fprintf(stderr, "Write error: %s\n", strerror(errno));
989
990                         return FALSE;
991                 }
992
993                 n -= cc;
994         }
995
996         if (!skipPadding(arch->fd, arch->pad))
997                 return FALSE;
998
999         return TRUE;
1000 }
1001
1002
1003 /*
1004  * Print one line listing the information about the specified archive member.
1005  */
1006 static void
1007 listMember(const Archive * arch)
1008 {
1009         printf("%s %6ld/%-6ld %8lu %s %s\n",
1010                modeString(arch->mode) + 1,
1011                (long) arch->uid,
1012                (long) arch->gid,
1013                (unsigned long) arch->size,
1014                timeString(arch->date),
1015                arch->name);
1016 }
1017
1018
1019 /* END CODE */