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