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