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