Added sfdisk. Ststic-ified a bunch of stuff.
[oweals/busybox.git] / archival / tar.c
1 /*
2  * Copyright (c) 1999 by David I. Bell
3  * Permission is granted to use, distribute, or modify this source,
4  * provided that this copyright notice remains intact.
5  *
6  * The "tar" command, taken from sash.
7  * This allows creation, extraction, and listing of tar files.
8  *
9  * Permission to distribute this code under the GPL has been granted.
10  * Modified for busybox by Erik Andersen <andersee@debian.org>
11  */
12
13
14 #include "internal.h"
15 #include <stdio.h>
16 #include <dirent.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <signal.h>
20 #include <time.h>
21
22
23 static const char tar_usage[] =
24     "Create, extract, or list files from a TAR file\n\n"
25     "usage: tar -[cxtvOf] [tarFileName] [FILE] ...\n"
26     "\tc=create, x=extract, t=list contents, v=verbose,\n"
27     "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
28
29
30
31 /*
32  * Tar file constants.
33  */
34 #define TAR_BLOCK_SIZE  512
35 #define TAR_NAME_SIZE   100
36
37
38 /*
39  * The POSIX (and basic GNU) tar header format.
40  * This structure is always embedded in a TAR_BLOCK_SIZE sized block
41  * with zero padding.  We only process this information minimally.
42  */
43 typedef struct {
44     char name[TAR_NAME_SIZE];
45     char mode[8];
46     char uid[8];
47     char gid[8];
48     char size[12];
49     char mtime[12];
50     char checkSum[8];
51     char typeFlag;
52     char linkName[TAR_NAME_SIZE];
53     char magic[6];
54     char version[2];
55     char uname[32];
56     char gname[32];
57     char devMajor[8];
58     char devMinor[8];
59     char prefix[155];
60 } TarHeader;
61
62 #define TAR_MAGIC       "ustar"
63 #define TAR_VERSION     "00"
64
65 #define TAR_TYPE_REGULAR        '0'
66 #define TAR_TYPE_HARD_LINK      '1'
67 #define TAR_TYPE_SOFT_LINK      '2'
68
69
70 /*
71  * Static data.
72  */
73 static int listFlag;
74 static int extractFlag;
75 static int createFlag;
76 static int verboseFlag;
77 static int tostdoutFlag;
78
79 static int inHeader;
80 static int badHeader;
81 static int errorFlag;
82 static int skipFileFlag;
83 static int warnedRoot;
84 static int eofFlag;
85 static long dataCc;
86 static int outFd;
87 static char outName[TAR_NAME_SIZE];
88
89
90 /*
91  * Static data associated with the tar file.
92  */
93 static const char *tarName;
94 static int tarFd;
95 static dev_t tarDev;
96 static ino_t tarInode;
97
98
99 /*
100  * Local procedures to restore files from a tar file.
101  */
102 static void readTarFile (int fileCount, char **fileTable);
103 static void readData (const char *cp, int count);
104 static long getOctal (const char *cp, int len);
105
106 static void readHeader (const TarHeader * hp,
107                         int fileCount, char **fileTable);
108
109
110 /*
111  * Local procedures to save files into a tar file.
112  */
113 static void saveFile (const char *fileName, int seeLinks);
114
115 static void saveRegularFile (const char *fileName,
116                              const struct stat *statbuf);
117
118 static void saveDirectory (const char *fileName,
119                            const struct stat *statbuf);
120
121 static int wantFileName (const char *fileName,
122                          int fileCount, char **fileTable);
123
124 static void writeHeader (const char *fileName, const struct stat *statbuf);
125
126 static void writeTarFile (int fileCount, char **fileTable);
127 static void writeTarBlock (const char *buf, int len);
128 static int putOctal (char *cp, int len, long value);
129
130
131 extern int tar_main (int argc, char **argv)
132 {
133     const char *options;
134
135     argc--;
136     argv++;
137
138     if (argc < 1) {
139         fprintf (stderr, "%s", tar_usage);
140         exit (FALSE);
141     }
142
143
144     errorFlag = FALSE;
145     extractFlag = FALSE;
146     createFlag = FALSE;
147     listFlag = FALSE;
148     verboseFlag = FALSE;
149     tostdoutFlag = FALSE;
150     tarName = NULL;
151     tarDev = 0;
152     tarInode = 0;
153     tarFd = -1;
154
155     /* 
156      * Parse the options.
157      */
158     options = *argv++;
159     argc--;
160
161     if (**argv == '-') {
162         for (; *options; options++) {
163             switch (*options) {
164             case 'f':
165                 if (tarName != NULL) {
166                     fprintf (stderr, "Only one 'f' option allowed\n");
167
168                     exit (FALSE);
169                 }
170
171                 tarName = *argv++;
172                 argc--;
173
174                 break;
175
176             case 't':
177                 listFlag = TRUE;
178                 break;
179
180             case 'x':
181                 extractFlag = TRUE;
182                 break;
183
184             case 'c':
185                 createFlag = TRUE;
186                 break;
187
188             case 'v':
189                 verboseFlag = TRUE;
190                 break;
191
192             case 'O':
193                 tostdoutFlag = TRUE;
194                 break;
195
196             case '-':
197                 break;
198
199             default:
200                 fprintf (stderr, "Unknown tar flag '%c'\n", *options);
201
202                 exit (FALSE);
203             }
204         }
205     }
206
207     /* 
208      * Validate the options.
209      */
210     if (extractFlag + listFlag + createFlag != 1) {
211         fprintf (stderr,
212                  "Exactly one of 'c', 'x' or 't' must be specified\n");
213
214         exit (FALSE);
215     }
216
217     /* 
218      * Do the correct type of action supplying the rest of the
219      * command line arguments as the list of files to process.
220      */
221     if (createFlag)
222         writeTarFile (argc, argv);
223     else
224         readTarFile (argc, argv);
225     if (errorFlag)
226         fprintf (stderr, "\n");
227     exit (errorFlag);
228 }
229
230
231 /*
232  * Read a tar file and extract or list the specified files within it.
233  * If the list is empty than all files are extracted or listed.
234  */
235 static void readTarFile (int fileCount, char **fileTable)
236 {
237     const char *cp;
238     int cc;
239     int inCc;
240     int blockSize;
241     char buf[BUF_SIZE];
242
243     skipFileFlag = FALSE;
244     badHeader = FALSE;
245     warnedRoot = FALSE;
246     eofFlag = FALSE;
247     inHeader = TRUE;
248     inCc = 0;
249     dataCc = 0;
250     outFd = -1;
251     blockSize = sizeof (buf);
252     cp = buf;
253
254     /* 
255      * Open the tar file for reading.
256      */
257     if ((tarName == NULL) || !strcmp (tarName, "-")) {
258         tarFd = STDIN;
259     } else
260         tarFd = open (tarName, O_RDONLY);
261
262     if (tarFd < 0) {
263         perror (tarName);
264         errorFlag = TRUE;
265         return;
266     }
267
268     /* 
269      * Read blocks from the file until an end of file header block
270      * has been seen.  (A real end of file from a read is an error.)
271      */
272     while (!eofFlag) {
273         /* 
274          * Read the next block of data if necessary.
275          * This will be a large block if possible, which we will
276          * then process in the small tar blocks.
277          */
278         if (inCc <= 0) {
279             cp = buf;
280             inCc = fullRead (tarFd, buf, blockSize);
281
282             if (inCc < 0) {
283                 perror (tarName);
284                 errorFlag = TRUE;
285                 goto done;
286             }
287
288             if (inCc == 0) {
289                 fprintf (stderr,
290                          "Unexpected end of file from \"%s\"", tarName);
291                 errorFlag = TRUE;
292                 goto done;
293             }
294         }
295
296         /* 
297          * If we are expecting a header block then examine it.
298          */
299         if (inHeader) {
300             readHeader ((const TarHeader *) cp, fileCount, fileTable);
301
302             cp += TAR_BLOCK_SIZE;
303             inCc -= TAR_BLOCK_SIZE;
304
305             continue;
306         }
307
308         /* 
309          * We are currently handling the data for a file.
310          * Process the minimum of the amount of data we have available
311          * and the amount left to be processed for the file.
312          */
313         cc = inCc;
314
315         if (cc > dataCc)
316             cc = dataCc;
317
318         readData (cp, cc);
319
320         /* 
321          * If the amount left isn't an exact multiple of the tar block
322          * size then round it up to the next block boundary since there
323          * is padding at the end of the file.
324          */
325         if (cc % TAR_BLOCK_SIZE)
326             cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
327
328         cp += cc;
329         inCc -= cc;
330     }
331
332   done:
333     /* 
334      * Close the tar file if needed.
335      */
336     if ((tarFd >= 0) && (close (tarFd) < 0))
337         perror (tarName);
338
339     /* 
340      * Close the output file if needed.
341      * This is only done here on a previous error and so no
342      * message is required on errors.
343      */
344     if (tostdoutFlag == FALSE) {
345         if (outFd >= 0)
346             (void) close (outFd);
347     }
348 }
349
350
351 /*
352  * Examine the header block that was just read.
353  * This can specify the information for another file, or it can mark
354  * the end of the tar file.
355  */
356 static void
357 readHeader (const TarHeader * hp, int fileCount, char **fileTable)
358 {
359     int mode;
360     int uid;
361     int gid;
362     int checkSum;
363     long size;
364     time_t mtime;
365     const char *name;
366     int cc;
367     int hardLink;
368     int softLink;
369
370     /* 
371      * If the block is completely empty, then this is the end of the
372      * archive file.  If the name is null, then just skip this header.
373      */
374     name = hp->name;
375
376     if (*name == '\0') {
377         for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
378             if (*name++)
379                 return;
380         }
381
382         eofFlag = TRUE;
383
384         return;
385     }
386
387     /* 
388      * There is another file in the archive to examine.
389      * Extract the encoded information and check it.
390      */
391     mode = getOctal (hp->mode, sizeof (hp->mode));
392     uid = getOctal (hp->uid, sizeof (hp->uid));
393     gid = getOctal (hp->gid, sizeof (hp->gid));
394     size = getOctal (hp->size, sizeof (hp->size));
395     mtime = getOctal (hp->mtime, sizeof (hp->mtime));
396     checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
397
398     if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
399         if (!badHeader)
400             fprintf (stderr, "Bad tar header, skipping\n");
401
402         badHeader = TRUE;
403
404         return;
405     }
406
407     badHeader = FALSE;
408     skipFileFlag = FALSE;
409
410     /* 
411      * Check for the file modes.
412      */
413     hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
414                 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
415
416     softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
417                 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
418
419     /* 
420      * Check for a directory or a regular file.
421      */
422     if (name[strlen (name) - 1] == '/')
423         mode |= S_IFDIR;
424     else if ((mode & S_IFMT) == 0)
425         mode |= S_IFREG;
426
427     /* 
428      * Check for absolute paths in the file.
429      * If we find any, then warn the user and make them relative.
430      */
431     if (*name == '/') {
432         while (*name == '/')
433             name++;
434
435         if (!warnedRoot) {
436             fprintf (stderr,
437                      "Absolute path detected, removing leading slashes\n");
438         }
439
440         warnedRoot = TRUE;
441     }
442
443     /* 
444      * See if we want this file to be restored.
445      * If not, then set up to skip it.
446      */
447     if (!wantFileName (name, fileCount, fileTable)) {
448         if (!hardLink && !softLink && S_ISREG (mode)) {
449             inHeader = (size == 0);
450             dataCc = size;
451         }
452
453         skipFileFlag = TRUE;
454
455         return;
456     }
457
458     /* 
459      * This file is to be handled.
460      * If we aren't extracting then just list information about the file.
461      */
462     if (!extractFlag) {
463         if (verboseFlag) {
464             printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
465                     uid, gid, size, timeString (mtime), name);
466         } else
467             printf ("%s", name);
468
469         if (hardLink)
470             printf (" (link to \"%s\")", hp->linkName);
471         else if (softLink)
472             printf (" (symlink to \"%s\")", hp->linkName);
473         else if (S_ISREG (mode)) {
474             inHeader = (size == 0);
475             dataCc = size;
476         }
477
478         printf ("\n");
479
480         return;
481     }
482
483     /* 
484      * We really want to extract the file.
485      */
486     if (verboseFlag)
487         printf ("x %s\n", name);
488
489     if (hardLink) {
490         if (link (hp->linkName, name) < 0)
491             perror (name);
492
493         return;
494     }
495
496     if (softLink) {
497 #ifdef  S_ISLNK
498         if (symlink (hp->linkName, name) < 0)
499             perror (name);
500 #else
501         fprintf (stderr, "Cannot create symbolic links\n");
502 #endif
503         return;
504     }
505
506     /* 
507      * If the file is a directory, then just create the path.
508      */
509     if (S_ISDIR (mode)) {
510         createPath (name, mode);
511
512         return;
513     }
514
515     /* 
516      * There is a file to write.
517      * First create the path to it if necessary with a default permission.
518      */
519     createPath (name, 0777);
520
521     inHeader = (size == 0);
522     dataCc = size;
523
524     /* 
525      * Start the output file.
526      */
527     if (tostdoutFlag == TRUE)
528         outFd = STDOUT;
529     else
530         outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
531
532     if (outFd < 0) {
533         perror (name);
534         skipFileFlag = TRUE;
535         return;
536     }
537
538     /* 
539      * If the file is empty, then that's all we need to do.
540      */
541     if (size == 0 && tostdoutFlag == FALSE) {
542         (void) close (outFd);
543         outFd = -1;
544     }
545 }
546
547
548 /*
549  * Handle a data block of some specified size that was read.
550  */
551 static void readData (const char *cp, int count)
552 {
553     /* 
554      * Reduce the amount of data left in this file.
555      * If there is no more data left, then we need to read
556      * the header again.
557      */
558     dataCc -= count;
559
560     if (dataCc <= 0)
561         inHeader = TRUE;
562
563     /* 
564      * If we aren't extracting files or this file is being
565      * skipped then do nothing more.
566      */
567     if (!extractFlag || skipFileFlag)
568         return;
569
570     /* 
571      * Write the data to the output file.
572      */
573     if (fullWrite (outFd, cp, count) < 0) {
574         perror (outName);
575         if (tostdoutFlag == FALSE) {
576             (void) close (outFd);
577             outFd = -1;
578         }
579         skipFileFlag = TRUE;
580         return;
581     }
582
583     /* 
584      * If the write failed, close the file and disable further
585      * writes to this file.
586      */
587     if (dataCc <= 0 && tostdoutFlag == FALSE) {
588         if (close (outFd))
589             perror (outName);
590
591         outFd = -1;
592     }
593 }
594
595
596 /*
597  * Write a tar file containing the specified files.
598  */
599 static void writeTarFile (int fileCount, char **fileTable)
600 {
601     struct stat statbuf;
602
603     /* 
604      * Make sure there is at least one file specified.
605      */
606     if (fileCount <= 0) {
607         fprintf (stderr, "No files specified to be saved\n");
608         errorFlag = TRUE;
609     }
610
611     /* 
612      * Create the tar file for writing.
613      */
614     if ((tarName == NULL) || !strcmp (tarName, "-")) {
615         tostdoutFlag = TRUE;
616         tarFd = STDOUT;
617     } else
618         tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
619
620     if (tarFd < 0) {
621         perror (tarName);
622         errorFlag = TRUE;
623         return;
624     }
625
626     /* 
627      * Get the device and inode of the tar file for checking later.
628      */
629     if (fstat (tarFd, &statbuf) < 0) {
630         perror (tarName);
631         errorFlag = TRUE;
632         goto done;
633     }
634
635     tarDev = statbuf.st_dev;
636     tarInode = statbuf.st_ino;
637
638     /* 
639      * Append each file name into the archive file.
640      * Follow symbolic links for these top level file names.
641      */
642     while (!errorFlag && (fileCount-- > 0)) {
643         saveFile (*fileTable++, FALSE);
644     }
645
646     /* 
647      * Now write an empty block of zeroes to end the archive.
648      */
649     writeTarBlock ("", 1);
650
651
652   done:
653     /* 
654      * Close the tar file and check for errors if it was opened.
655      */
656     if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
657         perror (tarName);
658 }
659
660
661 /*
662  * Save one file into the tar file.
663  * If the file is a directory, then this will recursively save all of
664  * the files and directories within the directory.  The seeLinks
665  * flag indicates whether or not we want to see symbolic links as
666  * they really are, instead of blindly following them.
667  */
668 static void saveFile (const char *fileName, int seeLinks)
669 {
670     int status;
671     int mode;
672     struct stat statbuf;
673
674     if (verboseFlag)
675         printf ("a %s\n", fileName);
676
677     /* 
678      * Check that the file name will fit in the header.
679      */
680     if (strlen (fileName) >= TAR_NAME_SIZE) {
681         fprintf (stderr, "%s: File name is too long\n", fileName);
682
683         return;
684     }
685
686     /* 
687      * Find out about the file.
688      */
689 #ifdef  S_ISLNK
690     if (seeLinks)
691         status = lstat (fileName, &statbuf);
692     else
693 #endif
694         status = stat (fileName, &statbuf);
695
696     if (status < 0) {
697         perror (fileName);
698
699         return;
700     }
701
702     /* 
703      * Make sure we aren't trying to save our file into itself.
704      */
705     if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
706         fprintf (stderr, "Skipping saving of archive file itself\n");
707
708         return;
709     }
710
711     /* 
712      * Check the type of file.
713      */
714     mode = statbuf.st_mode;
715
716     if (S_ISDIR (mode)) {
717         saveDirectory (fileName, &statbuf);
718
719         return;
720     }
721
722     if (S_ISREG (mode)) {
723         saveRegularFile (fileName, &statbuf);
724
725         return;
726     }
727
728     /* 
729      * The file is a strange type of file, ignore it.
730      */
731     fprintf (stderr, "%s: not a directory or regular file\n", fileName);
732 }
733
734
735 /*
736  * Save a regular file to the tar file.
737  */
738 static void
739 saveRegularFile (const char *fileName, const struct stat *statbuf)
740 {
741     int sawEof;
742     int fileFd;
743     int cc;
744     int dataCount;
745     long fullDataCount;
746     char data[TAR_BLOCK_SIZE * 16];
747
748     /* 
749      * Open the file for reading.
750      */
751     fileFd = open (fileName, O_RDONLY);
752
753     if (fileFd < 0) {
754         perror (fileName);
755
756         return;
757     }
758
759     /* 
760      * Write out the header for the file.
761      */
762     writeHeader (fileName, statbuf);
763
764     /* 
765      * Write the data blocks of the file.
766      * We must be careful to write the amount of data that the stat
767      * buffer indicated, even if the file has changed size.  Otherwise
768      * the tar file will be incorrect.
769      */
770     fullDataCount = statbuf->st_size;
771     sawEof = FALSE;
772
773     while (fullDataCount > 0) {
774         /* 
775          * Get the amount to write this iteration which is
776          * the minumum of the amount left to write and the
777          * buffer size.
778          */
779         dataCount = sizeof (data);
780
781         if (dataCount > fullDataCount)
782             dataCount = (int) fullDataCount;
783
784         /* 
785          * Read the data from the file if we haven't seen the
786          * end of file yet.
787          */
788         cc = 0;
789
790         if (!sawEof) {
791             cc = fullRead (fileFd, data, dataCount);
792
793             if (cc < 0) {
794                 perror (fileName);
795
796                 (void) close (fileFd);
797                 errorFlag = TRUE;
798
799                 return;
800             }
801
802             /* 
803              * If the file ended too soon, complain and set
804              * a flag so we will zero fill the rest of it.
805              */
806             if (cc < dataCount) {
807                 fprintf (stderr,
808                          "%s: Short read - zero filling", fileName);
809
810                 sawEof = TRUE;
811             }
812         }
813
814         /* 
815          * Zero fill the rest of the data if necessary.
816          */
817         if (cc < dataCount)
818             memset (data + cc, 0, dataCount - cc);
819
820         /* 
821          * Write the buffer to the TAR file.
822          */
823         writeTarBlock (data, dataCount);
824
825         fullDataCount -= dataCount;
826     }
827
828     /* 
829      * Close the file.
830      */
831     if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
832         fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
833 }
834
835
836 /*
837  * Save a directory and all of its files to the tar file.
838  */
839 static void saveDirectory (const char *dirName, const struct stat *statbuf)
840 {
841     DIR *dir;
842     struct dirent *entry;
843     int needSlash;
844     char fullName[NAME_MAX];
845
846     /* 
847      * Construct the directory name as used in the tar file by appending
848      * a slash character to it.
849      */
850     strcpy (fullName, dirName);
851     strcat (fullName, "/");
852
853     /* 
854      * Write out the header for the directory entry.
855      */
856     writeHeader (fullName, statbuf);
857
858     /* 
859      * Open the directory.
860      */
861     dir = opendir (dirName);
862
863     if (dir == NULL) {
864         fprintf (stderr, "Cannot read directory \"%s\": %s\n",
865                  dirName, strerror (errno));
866
867         return;
868     }
869
870     /* 
871      * See if a slash is needed.
872      */
873     needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
874
875     /* 
876      * Read all of the directory entries and check them,
877      * except for the current and parent directory entries.
878      */
879     while (!errorFlag && ((entry = readdir (dir)) != NULL)) {
880         if ((strcmp (entry->d_name, ".") == 0) ||
881             (strcmp (entry->d_name, "..") == 0)) {
882             continue;
883         }
884
885         /* 
886          * Build the full path name to the file.
887          */
888         strcpy (fullName, dirName);
889
890         if (needSlash)
891             strcat (fullName, "/");
892
893         strcat (fullName, entry->d_name);
894
895         /* 
896          * Write this file to the tar file, noticing whether or not
897          * the file is a symbolic link.
898          */
899         saveFile (fullName, TRUE);
900     }
901
902     /* 
903      * All done, close the directory.
904      */
905     closedir (dir);
906 }
907
908
909 /*
910  * Write a tar header for the specified file name and status.
911  * It is assumed that the file name fits.
912  */
913 static void writeHeader (const char *fileName, const struct stat *statbuf)
914 {
915     long checkSum;
916     const unsigned char *cp;
917     int len;
918     TarHeader header;
919
920     /* 
921      * Zero the header block in preparation for filling it in.
922      */
923     memset ((char *) &header, 0, sizeof (header));
924
925     /* 
926      * Fill in the header.
927      */
928     strcpy (header.name, fileName);
929
930     strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
931     strncpy (header.version, TAR_VERSION, sizeof (header.version));
932
933     putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
934     putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
935     putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
936     putOctal (header.size, sizeof (header.size), statbuf->st_size);
937     putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
938
939     header.typeFlag = TAR_TYPE_REGULAR;
940
941     /* 
942      * Calculate and store the checksum.
943      * This is the sum of all of the bytes of the header,
944      * with the checksum field itself treated as blanks.
945      */
946     memset (header.checkSum, ' ', sizeof (header.checkSum));
947
948     cp = (const unsigned char *) &header;
949     len = sizeof (header);
950     checkSum = 0;
951
952     while (len-- > 0)
953         checkSum += *cp++;
954
955     putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
956
957     /* 
958      * Write the tar header.
959      */
960     writeTarBlock ((const char *) &header, sizeof (header));
961 }
962
963
964 /*
965  * Write data to one or more blocks of the tar file.
966  * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
967  * The errorFlag static variable is set on an error.
968  */
969 static void writeTarBlock (const char *buf, int len)
970 {
971     int partialLength;
972     int completeLength;
973     char fullBlock[TAR_BLOCK_SIZE];
974
975     /* 
976      * If we had a write error before, then do nothing more.
977      */
978     if (errorFlag)
979         return;
980
981     /* 
982      * Get the amount of complete and partial blocks.
983      */
984     partialLength = len % TAR_BLOCK_SIZE;
985     completeLength = len - partialLength;
986
987     /* 
988      * Write all of the complete blocks.
989      */
990     if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
991         perror (tarName);
992
993         errorFlag = TRUE;
994
995         return;
996     }
997
998     /* 
999      * If there are no partial blocks left, we are done.
1000      */
1001     if (partialLength == 0)
1002         return;
1003
1004     /* 
1005      * Copy the partial data into a complete block, and pad the rest
1006      * of it with zeroes.
1007      */
1008     memcpy (fullBlock, buf + completeLength, partialLength);
1009     memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
1010
1011     /* 
1012      * Write the last complete block.
1013      */
1014     if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1015         perror (tarName);
1016
1017         errorFlag = TRUE;
1018     }
1019 }
1020
1021
1022 /*
1023  * Read an octal value in a field of the specified width, with optional
1024  * spaces on both sides of the number and with an optional null character
1025  * at the end.  Returns -1 on an illegal format.
1026  */
1027 static long getOctal (const char *cp, int len)
1028 {
1029     long val;
1030
1031     while ((len > 0) && (*cp == ' ')) {
1032         cp++;
1033         len--;
1034     }
1035
1036     if ((len == 0) || !isOctal (*cp))
1037         return -1;
1038
1039     val = 0;
1040
1041     while ((len > 0) && isOctal (*cp)) {
1042         val = val * 8 + *cp++ - '0';
1043         len--;
1044     }
1045
1046     while ((len > 0) && (*cp == ' ')) {
1047         cp++;
1048         len--;
1049     }
1050
1051     if ((len > 0) && *cp)
1052         return -1;
1053
1054     return val;
1055 }
1056
1057
1058 /*
1059  * Put an octal string into the specified buffer.
1060  * The number is zero and space padded and possibly null padded.
1061  * Returns TRUE if successful.
1062  */
1063 static int putOctal (char *cp, int len, long value)
1064 {
1065     int tempLength;
1066     char *tempString;
1067     char tempBuffer[32];
1068
1069     /* 
1070      * Create a string of the specified length with an initial space,
1071      * leading zeroes and the octal number, and a trailing null.
1072      */
1073     tempString = tempBuffer;
1074
1075     sprintf (tempString, " %0*lo", len - 2, value);
1076
1077     tempLength = strlen (tempString) + 1;
1078
1079     /* 
1080      * If the string is too large, suppress the leading space.
1081      */
1082     if (tempLength > len) {
1083         tempLength--;
1084         tempString++;
1085     }
1086
1087     /* 
1088      * If the string is still too large, suppress the trailing null.
1089      */
1090     if (tempLength > len)
1091         tempLength--;
1092
1093     /* 
1094      * If the string is still too large, fail.
1095      */
1096     if (tempLength > len)
1097         return FALSE;
1098
1099     /* 
1100      * Copy the string to the field.
1101      */
1102     memcpy (cp, tempString, len);
1103
1104     return TRUE;
1105 }
1106
1107
1108 /*
1109  * See if the specified file name belongs to one of the specified list
1110  * of path prefixes.  An empty list implies that all files are wanted.
1111  * Returns TRUE if the file is selected.
1112  */
1113 static int
1114 wantFileName (const char *fileName, int fileCount, char **fileTable)
1115 {
1116     const char *pathName;
1117     int fileLength;
1118     int pathLength;
1119
1120     /* 
1121      * If there are no files in the list, then the file is wanted.
1122      */
1123     if (fileCount == 0)
1124         return TRUE;
1125
1126     fileLength = strlen (fileName);
1127
1128     /* 
1129      * Check each of the test paths.
1130      */
1131     while (fileCount-- > 0) {
1132         pathName = *fileTable++;
1133
1134         pathLength = strlen (pathName);
1135
1136         if (fileLength < pathLength)
1137             continue;
1138
1139         if (memcmp (fileName, pathName, pathLength) != 0)
1140             continue;
1141
1142         if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
1143             return TRUE;
1144         }
1145     }
1146
1147     return FALSE;
1148 }
1149
1150
1151
1152 /* END CODE */