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