blob: 03da96735e6913bacdd9491c43504d0278667e4b [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
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
18const 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 */
45typedef 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 */
76static BOOL listFlag;
77static BOOL extractFlag;
78static BOOL createFlag;
79static BOOL verboseFlag;
80static BOOL tostdoutFlag;
81
82static BOOL inHeader;
83static BOOL badHeader;
84static BOOL errorFlag;
85static BOOL skipFileFlag;
86static BOOL warnedRoot;
87static BOOL eofFlag;
88static long dataCc;
89static int outFd;
90static char outName[TAR_NAME_SIZE];
91
92
93/*
94 * Static data associated with the tar file.
95 */
96static const char * tarName;
97static int tarFd;
98static dev_t tarDev;
99static ino_t tarInode;
100
101
102/*
103 * Local procedures to restore files from a tar file.
104 */
105static void readTarFile(int fileCount, char ** fileTable);
106static void readData(const char * cp, int count);
107static void createPath(const char * name, int mode);
108static long getOctal(const char * cp, int len);
109
110static void readHeader(const TarHeader * hp,
111 int fileCount, char ** fileTable);
112
113
114/*
115 * Local procedures to save files into a tar file.
116 */
117static void saveFile(const char * fileName, BOOL seeLinks);
118
119static void saveRegularFile(const char * fileName,
120 const struct stat * statbuf);
121
122static void saveDirectory(const char * fileName,
123 const struct stat * statbuf);
124
125static BOOL wantFileName(const char * fileName,
126 int fileCount, char ** fileTable);
127
128static void writeHeader(const char * fileName,
129 const struct stat * statbuf);
130
131static void writeTarFile(int fileCount, char ** fileTable);
132static void writeTarBlock(const char * buf, int len);
133static BOOL putOctal(char * cp, int len, long value);
134extern const char * modeString(int mode);
135extern const char * timeString(time_t timeVal);
136extern int fullWrite(int fd, const char * buf, int len);
137extern int fullRead(int fd, char * buf, int len);
138
139
140extern int
141tar_main(struct FileInfo *unused, int argc, char ** argv)
142{
143 const char * options;
144
145 argc--;
146 argv++;
147
148 if (argc < 1)
149 {
150 fprintf(stderr, "%s", tar_usage);
151 return 1;
152 }
153
154
155 errorFlag = FALSE;
156 extractFlag = FALSE;
157 createFlag = FALSE;
158 listFlag = FALSE;
159 verboseFlag = FALSE;
160 tostdoutFlag = FALSE;
161 tarName = NULL;
162 tarDev = 0;
163 tarInode = 0;
164 tarFd = -1;
165
166 /*
167 * Parse the options.
168 */
169 options = *argv++;
170 argc--;
171
172 if (**argv == '-') {
173 for (; *options; options++)
174 {
175 switch (*options)
176 {
177 case 'f':
178 if (tarName != NULL)
179 {
180 fprintf(stderr, "Only one 'f' option allowed\n");
181
182 return 1;
183 }
184
185 tarName = *argv++;
186 argc--;
187
188 break;
189
190 case 't':
191 listFlag = TRUE;
192 break;
193
194 case 'x':
195 extractFlag = TRUE;
196 break;
197
198 case 'c':
199 createFlag = TRUE;
200 break;
201
202 case 'v':
203 verboseFlag = TRUE;
204 break;
205
206 case 'O':
207 tostdoutFlag = TRUE;
208 break;
209
210 case '-':
211 break;
212
213 default:
214 fprintf(stderr, "Unknown tar flag '%c'\n", *options);
215
216 return 1;
217 }
218 }
219 }
220
221 /*
222 * Validate the options.
223 */
224 if (extractFlag + listFlag + createFlag != 1)
225 {
226 fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
227
228 return 1;
229 }
230
231 /*
232 * Do the correct type of action supplying the rest of the
233 * command line arguments as the list of files to process.
234 */
235 if (createFlag)
236 writeTarFile(argc, argv);
237 else
238 readTarFile(argc, argv);
239 if (errorFlag)
240 fprintf(stderr, "\n");
241 return( errorFlag);
242}
243
244
245/*
246 * Read a tar file and extract or list the specified files within it.
247 * If the list is empty than all files are extracted or listed.
248 */
249static void
250readTarFile(int fileCount, char ** fileTable)
251{
252 const char * cp;
253 int cc;
254 int inCc;
255 int blockSize;
256 char buf[BUF_SIZE];
257
258 skipFileFlag = FALSE;
259 badHeader = FALSE;
260 warnedRoot = FALSE;
261 eofFlag = FALSE;
262 inHeader = TRUE;
263 inCc = 0;
264 dataCc = 0;
265 outFd = -1;
266 blockSize = sizeof(buf);
267 cp = buf;
268
269 /*
270 * Open the tar file for reading.
271 */
272 if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
273 tarFd = STDIN;
274 }
275 else
276 tarFd = open(tarName, O_RDONLY);
277
278 if (tarFd < 0)
279 {
280 perror(tarName);
281 errorFlag = TRUE;
282 return;
283 }
284
285 /*
286 * Read blocks from the file until an end of file header block
287 * has been seen. (A real end of file from a read is an error.)
288 */
289 while (!eofFlag)
290 {
291 /*
292 * Read the next block of data if necessary.
293 * This will be a large block if possible, which we will
294 * then process in the small tar blocks.
295 */
296 if (inCc <= 0)
297 {
298 cp = buf;
299 inCc = fullRead(tarFd, buf, blockSize);
300
301 if (inCc < 0)
302 {
303 perror(tarName);
304 errorFlag=TRUE;
305 goto done;
306 }
307
308 if (inCc == 0)
309 {
310 fprintf(stderr,
311 "Unexpected end of file from \"%s\"",
312 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)
322 {
323 readHeader((const TarHeader *) cp, fileCount, fileTable);
324
325 cp += TAR_BLOCK_SIZE;
326 inCc -= TAR_BLOCK_SIZE;
327
328 continue;
329 }
330
331 /*
332 * We are currently handling the data for a file.
333 * Process the minimum of the amount of data we have available
334 * and the amount left to be processed for the file.
335 */
336 cc = inCc;
337
338 if (cc > dataCc)
339 cc = dataCc;
340
341 readData(cp, cc);
342
343 /*
344 * If the amount left isn't an exact multiple of the tar block
345 * size then round it up to the next block boundary since there
346 * is padding at the end of the file.
347 */
348 if (cc % TAR_BLOCK_SIZE)
349 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
350
351 cp += cc;
352 inCc -= cc;
353 }
354
355done:
356 /*
357 * Close the tar file if needed.
358 */
359 if ((tarFd >= 0) && (close(tarFd) < 0))
360 perror(tarName);
361
362 /*
363 * Close the output file if needed.
364 * This is only done here on a previous error and so no
365 * message is required on errors.
366 */
367 if (tostdoutFlag==FALSE) {
368 if (outFd >= 0)
369 (void) close(outFd);
370 }
371}
372
373
374/*
375 * Examine the header block that was just read.
376 * This can specify the information for another file, or it can mark
377 * the end of the tar file.
378 */
379static void
380readHeader(const TarHeader * hp, int fileCount, char ** fileTable)
381{
382 int mode;
383 int uid;
384 int gid;
385 int checkSum;
386 long size;
387 time_t mtime;
388 const char * name;
389 int cc;
390 BOOL hardLink;
391 BOOL softLink;
392
393 /*
394 * If the block is completely empty, then this is the end of the
395 * archive file. If the name is null, then just skip this header.
396 */
397 name = hp->name;
398
399 if (*name == '\0')
400 {
401 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--)
402 {
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
423 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0))
424 {
425 if (!badHeader)
426 fprintf(stderr, "Bad tar header, skipping\n");
427
428 badHeader = TRUE;
429
430 return;
431 }
432
433 badHeader = FALSE;
434 skipFileFlag = FALSE;
435
436 /*
437 * Check for the file modes.
438 */
439 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
440 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
441
442 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
443 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
444
445 /*
446 * Check for a directory or a regular file.
447 */
448 if (name[strlen(name) - 1] == '/')
449 mode |= S_IFDIR;
450 else if ((mode & S_IFMT) == 0)
451 mode |= S_IFREG;
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 {
459 while (*name == '/')
460 name++;
461
462 if (!warnedRoot)
463 {
464 fprintf(stderr,
465 "Absolute path detected, removing leading slashes\n");
466 }
467
468 warnedRoot = TRUE;
469 }
470
471 /*
472 * See if we want this file to be restored.
473 * If not, then set up to skip it.
474 */
475 if (!wantFileName(name, fileCount, fileTable))
476 {
477 if (!hardLink && !softLink && S_ISREG(mode))
478 {
479 inHeader = (size == 0);
480 dataCc = size;
481 }
482
483 skipFileFlag = TRUE;
484
485 return;
486 }
487
488 /*
489 * This file is to be handled.
490 * If we aren't extracting then just list information about the file.
491 */
492 if (!extractFlag)
493 {
494 if (verboseFlag)
495 {
496 printf("%s %3d/%-d %9ld %s %s", modeString(mode),
497 uid, gid, size, timeString(mtime), name);
498 }
499 else
500 printf("%s", name);
501
502 if (hardLink)
503 printf(" (link to \"%s\")", hp->linkName);
504 else if (softLink)
505 printf(" (symlink to \"%s\")", hp->linkName);
506 else if (S_ISREG(mode))
507 {
508 inHeader = (size == 0);
509 dataCc = size;
510 }
511
512 printf("\n");
513
514 return;
515 }
516
517 /*
518 * We really want to extract the file.
519 */
520 if (verboseFlag)
521 printf("x %s\n", name);
522
523 if (hardLink)
524 {
525 if (link(hp->linkName, name) < 0)
526 perror(name);
527
528 return;
529 }
530
531 if (softLink)
532 {
533#ifdef S_ISLNK
534 if (symlink(hp->linkName, name) < 0)
535 perror(name);
536#else
537 fprintf(stderr, "Cannot create symbolic links\n");
538#endif
539 return;
540 }
541
542 /*
543 * If the file is a directory, then just create the path.
544 */
545 if (S_ISDIR(mode))
546 {
547 createPath(name, mode);
548
549 return;
550 }
551
552 /*
553 * There is a file to write.
554 * First create the path to it if necessary with a default permission.
555 */
556 createPath(name, 0777);
557
558 inHeader = (size == 0);
559 dataCc = size;
560
561 /*
562 * Start the output file.
563 */
564 if (tostdoutFlag==TRUE)
565 outFd = STDOUT;
566 else
567 outFd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
568
569 if (outFd < 0)
570 {
571 perror(name);
572 skipFileFlag = TRUE;
573 return;
574 }
575
576 /*
577 * If the file is empty, then that's all we need to do.
578 */
579 if (size == 0 && tostdoutFlag == FALSE)
580 {
581 (void) close(outFd);
582 outFd = -1;
583 }
584}
585
586
587/*
588 * Handle a data block of some specified size that was read.
589 */
590static void
591readData(const char * cp, int count)
592{
593 /*
594 * Reduce the amount of data left in this file.
595 * If there is no more data left, then we need to read
596 * the header again.
597 */
598 dataCc -= count;
599
600 if (dataCc <= 0)
601 inHeader = TRUE;
602
603 /*
604 * If we aren't extracting files or this file is being
605 * skipped then do nothing more.
606 */
607 if (!extractFlag || skipFileFlag)
608 return;
609
610 /*
611 * Write the data to the output file.
612 */
613 if (fullWrite(outFd, cp, count) < 0)
614 {
615 perror(outName);
616 if (tostdoutFlag==FALSE) {
617 (void) close(outFd);
618 outFd = -1;
619 }
620 skipFileFlag = TRUE;
621 return;
622 }
623
624 /*
625 * If the write failed, close the file and disable further
626 * writes to this file.
627 */
628 if (dataCc <= 0 && tostdoutFlag==FALSE)
629 {
630 if (close(outFd))
631 perror(outName);
632
633 outFd = -1;
634 }
635}
636
637
638/*
639 * Write a tar file containing the specified files.
640 */
641static void
642writeTarFile(int fileCount, char ** fileTable)
643{
644 struct stat statbuf;
645
646 /*
647 * Make sure there is at least one file specified.
648 */
649 if (fileCount <= 0)
650 {
651 fprintf(stderr, "No files specified to be saved\n");
652 errorFlag=TRUE;
653 }
654
655 /*
656 * Create the tar file for writing.
657 */
658 if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
659 tostdoutFlag = TRUE;
660 tarFd = STDOUT;
661 }
662 else
663 tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
664
665 if (tarFd < 0)
666 {
667 perror(tarName);
668 errorFlag=TRUE;
669 return;
670 }
671
672 /*
673 * Get the device and inode of the tar file for checking later.
674 */
675 if (fstat(tarFd, &statbuf) < 0)
676 {
677 perror(tarName);
678 errorFlag = TRUE;
679 goto done;
680 }
681
682 tarDev = statbuf.st_dev;
683 tarInode = statbuf.st_ino;
684
685 /*
686 * Append each file name into the archive file.
687 * Follow symbolic links for these top level file names.
688 */
689 while (!errorFlag && (fileCount-- > 0))
690 {
691 saveFile(*fileTable++, FALSE);
692 }
693
694 /*
695 * Now write an empty block of zeroes to end the archive.
696 */
697 writeTarBlock("", 1);
698
699
700done:
701 /*
702 * Close the tar file and check for errors if it was opened.
703 */
704 if ( (tostdoutFlag==FALSE) && (tarFd >= 0) && (close(tarFd) < 0))
705 perror(tarName);
706}
707
708
709/*
710 * Save one file into the tar file.
711 * If the file is a directory, then this will recursively save all of
712 * the files and directories within the directory. The seeLinks
713 * flag indicates whether or not we want to see symbolic links as
714 * they really are, instead of blindly following them.
715 */
716static void
717saveFile(const char * fileName, BOOL seeLinks)
718{
719 int status;
720 int mode;
721 struct stat statbuf;
722
723 if (verboseFlag)
724 printf("a %s\n", fileName);
725
726 /*
727 * Check that the file name will fit in the header.
728 */
729 if (strlen(fileName) >= TAR_NAME_SIZE)
730 {
731 fprintf(stderr, "%s: File name is too long\n", fileName);
732
733 return;
734 }
735
736 /*
737 * Find out about the file.
738 */
739#ifdef S_ISLNK
740 if (seeLinks)
741 status = lstat(fileName, &statbuf);
742 else
743#endif
744 status = stat(fileName, &statbuf);
745
746 if (status < 0)
747 {
748 perror(fileName);
749
750 return;
751 }
752
753 /*
754 * Make sure we aren't trying to save our file into itself.
755 */
756 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode))
757 {
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 {
770 saveDirectory(fileName, &statbuf);
771
772 return;
773 }
774
775 if (S_ISREG(mode))
776 {
777 saveRegularFile(fileName, &statbuf);
778
779 return;
780 }
781
782 /*
783 * The file is a strange type of file, ignore it.
784 */
785 fprintf(stderr, "%s: not a directory or regular file\n", fileName);
786}
787
788
789/*
790 * Save a regular file to the tar file.
791 */
792static void
793saveRegularFile(const char * fileName, const struct stat * statbuf)
794{
795 BOOL sawEof;
796 int fileFd;
797 int cc;
798 int dataCount;
799 long fullDataCount;
800 char data[TAR_BLOCK_SIZE * 16];
801
802 /*
803 * Open the file for reading.
804 */
805 fileFd = open(fileName, O_RDONLY);
806
807 if (fileFd < 0)
808 {
809 perror(fileName);
810
811 return;
812 }
813
814 /*
815 * Write out the header for the file.
816 */
817 writeHeader(fileName, statbuf);
818
819 /*
820 * Write the data blocks of the file.
821 * We must be careful to write the amount of data that the stat
822 * buffer indicated, even if the file has changed size. Otherwise
823 * the tar file will be incorrect.
824 */
825 fullDataCount = statbuf->st_size;
826 sawEof = FALSE;
827
828 while (fullDataCount > 0)
829 {
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)
847 {
848 cc = fullRead(fileFd, data, dataCount);
849
850 if (cc < 0)
851 {
852 perror(fileName);
853
854 (void) close(fileFd);
855 errorFlag = TRUE;
856
857 return;
858 }
859
860 /*
861 * If the file ended too soon, complain and set
862 * a flag so we will zero fill the rest of it.
863 */
864 if (cc < dataCount)
865 {
866 fprintf(stderr,
867 "%s: Short read - zero filling",
868 fileName);
869
870 sawEof = TRUE;
871 }
872 }
873
874 /*
875 * Zero fill the rest of the data if necessary.
876 */
877 if (cc < dataCount)
878 memset(data + cc, 0, dataCount - cc);
879
880 /*
881 * Write the buffer to the TAR file.
882 */
883 writeTarBlock(data, dataCount);
884
885 fullDataCount -= dataCount;
886 }
887
888 /*
889 * Close the file.
890 */
891 if ( (tostdoutFlag==FALSE) && close(fileFd) < 0)
892 fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
893}
894
895
896/*
897 * Save a directory and all of its files to the tar file.
898 */
899static void
900saveDirectory(const char * dirName, const struct stat * statbuf)
901{
902 DIR * dir;
903 struct dirent * entry;
904 BOOL needSlash;
905 char fullName[PATH_LEN];
906
907 /*
908 * Construct the directory name as used in the tar file by appending
909 * a slash character to it.
910 */
911 strcpy(fullName, dirName);
912 strcat(fullName, "/");
913
914 /*
915 * Write out the header for the directory entry.
916 */
917 writeHeader(fullName, statbuf);
918
919 /*
920 * Open the directory.
921 */
922 dir = opendir(dirName);
923
924 if (dir == NULL)
925 {
926 fprintf(stderr, "Cannot read directory \"%s\": %s\n",
927 dirName, strerror(errno));
928
929 return;
930 }
931
932 /*
933 * See if a slash is needed.
934 */
935 needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
936
937 /*
938 * Read all of the directory entries and check them,
939 * except for the current and parent directory entries.
940 */
941 while (!errorFlag && ((entry = readdir(dir)) != NULL))
942 {
943 if ((strcmp(entry->d_name, ".") == 0) ||
944 (strcmp(entry->d_name, "..") == 0))
945 {
946 continue;
947 }
948
949 /*
950 * Build the full path name to the file.
951 */
952 strcpy(fullName, dirName);
953
954 if (needSlash)
955 strcat(fullName, "/");
956
957 strcat(fullName, entry->d_name);
958
959 /*
960 * Write this file to the tar file, noticing whether or not
961 * the file is a symbolic link.
962 */
963 saveFile(fullName, TRUE);
964 }
965
966 /*
967 * All done, close the directory.
968 */
969 closedir(dir);
970}
971
972
973/*
974 * Write a tar header for the specified file name and status.
975 * It is assumed that the file name fits.
976 */
977static void
978writeHeader(const char * fileName, const struct stat * statbuf)
979{
980 long checkSum;
981 const unsigned char * cp;
982 int len;
983 TarHeader header;
984
985 /*
986 * Zero the header block in preparation for filling it in.
987 */
988 memset((char *) &header, 0, sizeof(header));
989
990 /*
991 * Fill in the header.
992 */
993 strcpy(header.name, fileName);
994
995 strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
996 strncpy(header.version, TAR_VERSION, sizeof(header.version));
997
998 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
999 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
1000 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
1001 putOctal(header.size, sizeof(header.size), statbuf->st_size);
1002 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
1003
1004 header.typeFlag = TAR_TYPE_REGULAR;
1005
1006 /*
1007 * Calculate and store the checksum.
1008 * This is the sum of all of the bytes of the header,
1009 * with the checksum field itself treated as blanks.
1010 */
1011 memset(header.checkSum, ' ', sizeof(header.checkSum));
1012
1013 cp = (const unsigned char *) &header;
1014 len = sizeof(header);
1015 checkSum = 0;
1016
1017 while (len-- > 0)
1018 checkSum += *cp++;
1019
1020 putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
1021
1022 /*
1023 * Write the tar header.
1024 */
1025 writeTarBlock((const char *) &header, sizeof(header));
1026}
1027
1028
1029/*
1030 * Write data to one or more blocks of the tar file.
1031 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1032 * The errorFlag static variable is set on an error.
1033 */
1034static void
1035writeTarBlock(const char * buf, int len)
1036{
1037 int partialLength;
1038 int completeLength;
1039 char fullBlock[TAR_BLOCK_SIZE];
1040
1041 /*
1042 * If we had a write error before, then do nothing more.
1043 */
1044 if (errorFlag)
1045 return;
1046
1047 /*
1048 * Get the amount of complete and partial blocks.
1049 */
1050 partialLength = len % TAR_BLOCK_SIZE;
1051 completeLength = len - partialLength;
1052
1053 /*
1054 * Write all of the complete blocks.
1055 */
1056 if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength))
1057 {
1058 perror(tarName);
1059
1060 errorFlag = TRUE;
1061
1062 return;
1063 }
1064
1065 /*
1066 * If there are no partial blocks left, we are done.
1067 */
1068 if (partialLength == 0)
1069 return;
1070
1071 /*
1072 * Copy the partial data into a complete block, and pad the rest
1073 * of it with zeroes.
1074 */
1075 memcpy(fullBlock, buf + completeLength, partialLength);
1076 memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
1077
1078 /*
1079 * Write the last complete block.
1080 */
1081 if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE))
1082 {
1083 perror(tarName);
1084
1085 errorFlag = TRUE;
1086 }
1087}
1088
1089
1090/*
1091 * Attempt to create the directories along the specified path, except for
1092 * the final component. The mode is given for the final directory only,
1093 * while all previous ones get default protections. Errors are not reported
1094 * here, as failures to restore files can be reported later.
1095 */
1096static void
1097createPath(const char * name, int mode)
1098{
1099 char * cp;
1100 char * cpOld;
1101 char buf[TAR_NAME_SIZE];
1102
1103 strcpy(buf, name);
1104
1105 cp = strchr(buf, '/');
1106
1107 while (cp)
1108 {
1109 cpOld = cp;
1110 cp = strchr(cp + 1, '/');
1111
1112 *cpOld = '\0';
1113
1114 if (mkdir(buf, cp ? 0777 : mode) == 0)
1115 printf("Directory \"%s\" created\n", buf);
1116
1117 *cpOld = '/';
1118 }
1119}
1120
1121
1122/*
1123 * Read an octal value in a field of the specified width, with optional
1124 * spaces on both sides of the number and with an optional null character
1125 * at the end. Returns -1 on an illegal format.
1126 */
1127static long
1128getOctal(const char * cp, int len)
1129{
1130 long val;
1131
1132 while ((len > 0) && (*cp == ' '))
1133 {
1134 cp++;
1135 len--;
1136 }
1137
1138 if ((len == 0) || !isOctal(*cp))
1139 return -1;
1140
1141 val = 0;
1142
1143 while ((len > 0) && isOctal(*cp))
1144 {
1145 val = val * 8 + *cp++ - '0';
1146 len--;
1147 }
1148
1149 while ((len > 0) && (*cp == ' '))
1150 {
1151 cp++;
1152 len--;
1153 }
1154
1155 if ((len > 0) && *cp)
1156 return -1;
1157
1158 return val;
1159}
1160
1161
1162/*
1163 * Put an octal string into the specified buffer.
1164 * The number is zero and space padded and possibly null padded.
1165 * Returns TRUE if successful.
1166 */
1167static BOOL
1168putOctal(char * cp, int len, long value)
1169{
1170 int tempLength;
1171 char * tempString;
1172 char tempBuffer[32];
1173
1174 /*
1175 * Create a string of the specified length with an initial space,
1176 * leading zeroes and the octal number, and a trailing null.
1177 */
1178 tempString = tempBuffer;
1179
1180 sprintf(tempString, " %0*lo", len - 2, value);
1181
1182 tempLength = strlen(tempString) + 1;
1183
1184 /*
1185 * If the string is too large, suppress the leading space.
1186 */
1187 if (tempLength > len)
1188 {
1189 tempLength--;
1190 tempString++;
1191 }
1192
1193 /*
1194 * If the string is still too large, suppress the trailing null.
1195 */
1196 if (tempLength > len)
1197 tempLength--;
1198
1199 /*
1200 * If the string is still too large, fail.
1201 */
1202 if (tempLength > len)
1203 return FALSE;
1204
1205 /*
1206 * Copy the string to the field.
1207 */
1208 memcpy(cp, tempString, len);
1209
1210 return TRUE;
1211}
1212
1213
1214/*
1215 * See if the specified file name belongs to one of the specified list
1216 * of path prefixes. An empty list implies that all files are wanted.
1217 * Returns TRUE if the file is selected.
1218 */
1219static BOOL
1220wantFileName(const char * fileName, int fileCount, char ** fileTable)
1221{
1222 const char * pathName;
1223 int fileLength;
1224 int pathLength;
1225
1226 /*
1227 * If there are no files in the list, then the file is wanted.
1228 */
1229 if (fileCount == 0)
1230 return TRUE;
1231
1232 fileLength = strlen(fileName);
1233
1234 /*
1235 * Check each of the test paths.
1236 */
1237 while (fileCount-- > 0)
1238 {
1239 pathName = *fileTable++;
1240
1241 pathLength = strlen(pathName);
1242
1243 if (fileLength < pathLength)
1244 continue;
1245
1246 if (memcmp(fileName, pathName, pathLength) != 0)
1247 continue;
1248
1249 if ((fileLength == pathLength) ||
1250 (fileName[pathLength] == '/'))
1251 {
1252 return TRUE;
1253 }
1254 }
1255
1256 return FALSE;
1257}
1258
1259
1260
1261/*
1262 * Return the standard ls-like mode string from a file mode.
1263 * This is static and so is overwritten on each call.
1264 */
1265const char *
1266modeString(int mode)
1267{
1268 static char buf[12];
1269
1270 strcpy(buf, "----------");
1271
1272 /*
1273 * Fill in the file type.
1274 */
1275 if (S_ISDIR(mode))
1276 buf[0] = 'd';
1277 if (S_ISCHR(mode))
1278 buf[0] = 'c';
1279 if (S_ISBLK(mode))
1280 buf[0] = 'b';
1281 if (S_ISFIFO(mode))
1282 buf[0] = 'p';
1283#ifdef S_ISLNK
1284 if (S_ISLNK(mode))
1285 buf[0] = 'l';
1286#endif
1287#ifdef S_ISSOCK
1288 if (S_ISSOCK(mode))
1289 buf[0] = 's';
1290#endif
1291
1292 /*
1293 * Now fill in the normal file permissions.
1294 */
1295 if (mode & S_IRUSR)
1296 buf[1] = 'r';
1297 if (mode & S_IWUSR)
1298 buf[2] = 'w';
1299 if (mode & S_IXUSR)
1300 buf[3] = 'x';
1301 if (mode & S_IRGRP)
1302 buf[4] = 'r';
1303 if (mode & S_IWGRP)
1304 buf[5] = 'w';
1305 if (mode & S_IXGRP)
1306 buf[6] = 'x';
1307 if (mode & S_IROTH)
1308 buf[7] = 'r';
1309 if (mode & S_IWOTH)
1310 buf[8] = 'w';
1311 if (mode & S_IXOTH)
1312 buf[9] = 'x';
1313
1314 /*
1315 * Finally fill in magic stuff like suid and sticky text.
1316 */
1317 if (mode & S_ISUID)
1318 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
1319 if (mode & S_ISGID)
1320 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
1321 if (mode & S_ISVTX)
1322 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
1323
1324 return buf;
1325}
1326
1327
1328/*
1329 * Get the time string to be used for a file.
1330 * This is down to the minute for new files, but only the date for old files.
1331 * The string is returned from a static buffer, and so is overwritten for
1332 * each call.
1333 */
1334const char *
1335timeString(time_t timeVal)
1336{
1337 time_t now;
1338 char * str;
1339 static char buf[26];
1340
1341 time(&now);
1342
1343 str = ctime(&timeVal);
1344
1345 strcpy(buf, &str[4]);
1346 buf[12] = '\0';
1347
1348 if ((timeVal > now) || (timeVal < now - 365*24*60*60L))
1349 {
1350 strcpy(&buf[7], &str[20]);
1351 buf[11] = '\0';
1352 }
1353
1354 return buf;
1355}
1356
1357
1358
1359/*
1360 * Write all of the supplied buffer out to a file.
1361 * This does multiple writes as necessary.
1362 * Returns the amount written, or -1 on an error.
1363 */
1364int
1365fullWrite(int fd, const char * buf, int len)
1366{
1367 int cc;
1368 int total;
1369
1370 total = 0;
1371
1372 while (len > 0)
1373 {
1374 cc = write(fd, buf, len);
1375
1376 if (cc < 0)
1377 return -1;
1378
1379 buf += cc;
1380 total+= cc;
1381 len -= cc;
1382 }
1383
1384 return total;
1385}
1386
1387
1388/*
1389 * Read all of the supplied buffer from a file.
1390 * This does multiple reads as necessary.
1391 * Returns the amount read, or -1 on an error.
1392 * A short read is returned on an end of file.
1393 */
1394int
1395fullRead(int fd, char * buf, int len)
1396{
1397 int cc;
1398 int total;
1399
1400 total = 0;
1401
1402 while (len > 0)
1403 {
1404 cc = read(fd, buf, len);
1405
1406 if (cc < 0)
1407 return -1;
1408
1409 if (cc == 0)
1410 break;
1411
1412 buf += cc;
1413 total+= cc;
1414 len -= cc;
1415 }
1416
1417 return total;
1418}
1419
1420
1421
1422#endif
1423/* END CODE */
1424
1425