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