blob: 498d4a3004512645573dc91ce50e9d32a9a3ac55 [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);
Eric Andersencc8ed391999-10-05 16:24:54 +0000134
135
136extern int
Eric Andersen17d49ef1999-10-06 20:25:32 +0000137tar_main(int argc, char ** argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000138{
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 */
245static void
246readTarFile(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
351done:
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 */
375static void
376readHeader(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 */
586static void
587readData(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 */
637static void
638writeTarFile(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
696done:
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 */
712static void
713saveFile(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 */
788static void
789saveRegularFile(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 */
895static void
896saveDirectory(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 */
973static void
974writeHeader(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 */
1030static void
1031writeTarBlock(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 */
1092static void
1093createPath(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 */
1123static long
1124getOctal(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 */
1163static BOOL
1164putOctal(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 */
1215static BOOL
1216wantFileName(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
Eric Andersencc8ed391999-10-05 16:24:54 +00001257#endif
1258/* END CODE */
1259
1260