diff options
author | Erik Andersen <andersen@codepoet.org> | 2000-04-04 18:39:50 +0000 |
---|---|---|
committer | Erik Andersen <andersen@codepoet.org> | 2000-04-04 18:39:50 +0000 |
commit | 68a9ea4208d5661de225fec9be3ffff8b02b8d66 (patch) | |
tree | cdda0600efe3f7129e9e17809ae168dda63be66a | |
parent | 183da4ade108945f94117a633045cfd6f4ff813a (diff) | |
download | busybox-w32-68a9ea4208d5661de225fec9be3ffff8b02b8d66.tar.gz busybox-w32-68a9ea4208d5661de225fec9be3ffff8b02b8d66.tar.bz2 busybox-w32-68a9ea4208d5661de225fec9be3ffff8b02b8d66.zip |
Update tar so creation of tarballs is much closer to working...
-Erik
-rw-r--r-- | archival/tar.c | 195 | ||||
-rw-r--r-- | tar.c | 195 |
2 files changed, 252 insertions, 138 deletions
diff --git a/archival/tar.c b/archival/tar.c index af0e4f8ef..f9b3e1813 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1,12 +1,12 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Mini tar implementation for busybox | ||
3 | * | 4 | * |
4 | * Mini tar implementation for busybox Note, that as of BusyBox 0.43 tar has | 5 | * Note, that as of BusyBox 0.43 tar has been completely rewritten from the |
5 | * been completely rewritten from the ground up. It still has remnents of the | 6 | * ground up. It still has remnents of the old code lying about, but it pretty |
6 | * old code lying about, but it pretty different (i.e. cleaner, less global | 7 | * different (i.e. cleaner, less global variables, etc) |
7 | * variables, etc) | ||
8 | * | 8 | * |
9 | * Copyright (C) 1999 by Lineo, inc. | 9 | * Copyright (C) 2000 by Lineo, inc. |
10 | * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> | 10 | * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> |
11 | * | 11 | * |
12 | * Based in part in the tar implementation in sash | 12 | * Based in part in the tar implementation in sash |
@@ -15,7 +15,7 @@ | |||
15 | * provided that this copyright notice remains intact. | 15 | * provided that this copyright notice remains intact. |
16 | * Permission to distribute sash derived code under the GPL has been granted. | 16 | * Permission to distribute sash derived code under the GPL has been granted. |
17 | * | 17 | * |
18 | * Based in part on the tar implementation in busybox-0.28 | 18 | * Based in part on the tar implementation from busybox-0.28 |
19 | * Copyright (C) 1995 Bruce Perens | 19 | * Copyright (C) 1995 Bruce Perens |
20 | * This is free software under the GNU General Public License. | 20 | * This is free software under the GNU General Public License. |
21 | * | 21 | * |
@@ -162,8 +162,8 @@ static int readTarFile(const char* tarName, int extractFlag, int listFlag, | |||
162 | 162 | ||
163 | #ifdef BB_FEATURE_TAR_CREATE | 163 | #ifdef BB_FEATURE_TAR_CREATE |
164 | /* Local procedures to save files into a tar file. */ | 164 | /* Local procedures to save files into a tar file. */ |
165 | static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | 165 | static int writeTarFile(const char* tarName, int tostdoutFlag, |
166 | int tostdoutFlag, int verboseFlag, int argc, char **argv); | 166 | int verboseFlag, int argc, char **argv); |
167 | static int putOctal(char *cp, int len, long value); | 167 | static int putOctal(char *cp, int len, long value); |
168 | 168 | ||
169 | #endif | 169 | #endif |
@@ -249,7 +249,7 @@ extern int tar_main(int argc, char **argv) | |||
249 | #ifndef BB_FEATURE_TAR_CREATE | 249 | #ifndef BB_FEATURE_TAR_CREATE |
250 | fatalError( "This version of tar was not compiled with tar creation support.\n"); | 250 | fatalError( "This version of tar was not compiled with tar creation support.\n"); |
251 | #else | 251 | #else |
252 | exit(writeTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag, argc, argv)); | 252 | exit(writeTarFile(tarName, tostdoutFlag, verboseFlag, argc, argv)); |
253 | #endif | 253 | #endif |
254 | } else { | 254 | } else { |
255 | exit(readTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag)); | 255 | exit(readTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag)); |
@@ -410,8 +410,6 @@ tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag) | |||
410 | mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)); | 410 | mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)); |
411 | } else if (S_ISFIFO(header->mode)) { | 411 | } else if (S_ISFIFO(header->mode)) { |
412 | mkfifo(header->name, header->mode); | 412 | mkfifo(header->name, header->mode); |
413 | } else { | ||
414 | open(header->name, O_WRONLY | O_CREAT | O_TRUNC, header->mode); | ||
415 | } | 413 | } |
416 | 414 | ||
417 | /* Now set permissions etc for the new directory */ | 415 | /* Now set permissions etc for the new directory */ |
@@ -625,6 +623,21 @@ endgame: | |||
625 | 623 | ||
626 | #ifdef BB_FEATURE_TAR_CREATE | 624 | #ifdef BB_FEATURE_TAR_CREATE |
627 | 625 | ||
626 | /* Some info to be carried along when creating a new tarball */ | ||
627 | struct TarBallInfo | ||
628 | { | ||
629 | char* fileName; /* File name of the tarball */ | ||
630 | int tarFd; /* Open-for-write file descriptor | ||
631 | for the tarball */ | ||
632 | struct stat statBuf; /* Stat info for the tarball, letting | ||
633 | us know the inode and device that the | ||
634 | tarball lives, so we can avoid trying | ||
635 | to include the tarball into itself */ | ||
636 | int verboseFlag; /* Whether to print extra stuff or not */ | ||
637 | }; | ||
638 | typedef struct TarBallInfo TarBallInfo; | ||
639 | |||
640 | |||
628 | /* Put an octal string into the specified buffer. | 641 | /* Put an octal string into the specified buffer. |
629 | * The number is zero and space padded and possibly null padded. | 642 | * The number is zero and space padded and possibly null padded. |
630 | * Returns TRUE if successful. */ | 643 | * Returns TRUE if successful. */ |
@@ -662,41 +675,55 @@ static int putOctal (char *cp, int len, long value) | |||
662 | return TRUE; | 675 | return TRUE; |
663 | } | 676 | } |
664 | 677 | ||
665 | /* Write out a tar header for the specified file */ | 678 | /* Write out a tar header for the specified file/directory/whatever */ |
666 | static int | 679 | static int |
667 | writeTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) | 680 | writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *statbuf) |
668 | { | 681 | { |
669 | int i; | 682 | //int i; |
670 | long chksum, sum; | 683 | //long chksum, sum; |
671 | unsigned char *s = (unsigned char *)rawHeader; | 684 | |
672 | 685 | if (*fileName=='/') { | |
673 | struct TarHeader header; | 686 | static int alreadyWarned=FALSE; |
674 | 687 | if (alreadyWarned==FALSE) { | |
675 | strcpy(header.name, fileName); | 688 | errorMsg("tar: Removing leading '/' from member names\n"); |
676 | putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777); | 689 | alreadyWarned=TRUE; |
677 | putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); | 690 | } |
678 | putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); | 691 | strcpy(header->name, fileName+1); |
679 | putOctal(header.size, sizeof(header.size), statbuf->st_size); | 692 | } |
680 | putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); | 693 | else { |
681 | 694 | strcpy(header->name, fileName); | |
682 | if (S_ISLNK(statbuf.st_mode)) { | 695 | } |
683 | header.type = LNKTYPE; | 696 | putOctal(header->mode, sizeof(header->mode), statbuf->st_mode & 0777); |
684 | // Handle SYMTYPE | 697 | putOctal(header->uid, sizeof(header->uid), statbuf->st_uid); |
685 | } else if (S_ISDIR(statbuf.st_mode)) { | 698 | putOctal(header->gid, sizeof(header->gid), statbuf->st_gid); |
686 | header.type = DIRTYPE; | 699 | putOctal(header->size, sizeof(header->size), statbuf->st_size); |
687 | } else if (S_ISCHR(statbuf.st_mode)) { | 700 | putOctal(header->mtime, sizeof(header->mtime), statbuf->st_mtime); |
688 | header.type = CHRTYPE; | 701 | |
689 | } else if (S_ISBLK(statbuf.st_mode)) { | 702 | if (S_ISLNK(statbuf->st_mode)) { |
690 | header.type = BLKTYPE; | 703 | header->typeflag = LNKTYPE; |
691 | } else if (S_ISFIFO(statbuf.st_mode)) { | 704 | // TODO -- Handle SYMTYPE |
692 | header.type = FIFOTYPE; | 705 | } else if (S_ISDIR(statbuf->st_mode)) { |
693 | } else if (S_ISSOCK(statbuf.st_mode)) { | 706 | header->typeflag = DIRTYPE; |
694 | header.type = S_ISSOCK; | 707 | strncat(header->name, "/", sizeof(header->name)); |
695 | } else if (S_ISLNK(statbuf.st_mode)) { | 708 | } else if (S_ISCHR(statbuf->st_mode)) { |
696 | header.type = LNKTYPE; | 709 | header->typeflag = CHRTYPE; |
697 | } else if (S_ISLNK(statbuf.st_mode)) { | 710 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); |
698 | header.type = REGTYPE; | 711 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); |
712 | } else if (S_ISBLK(statbuf->st_mode)) { | ||
713 | header->typeflag = BLKTYPE; | ||
714 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); | ||
715 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); | ||
716 | } else if (S_ISFIFO(statbuf->st_mode)) { | ||
717 | header->typeflag = FIFOTYPE; | ||
718 | } else if (S_ISLNK(statbuf->st_mode)) { | ||
719 | header->typeflag = LNKTYPE; | ||
720 | } else if (S_ISLNK(statbuf->st_mode)) { | ||
721 | header->typeflag = REGTYPE; | ||
722 | } else { | ||
723 | return ( FALSE); | ||
699 | } | 724 | } |
725 | return ( TRUE); | ||
726 | |||
700 | #if 0 | 727 | #if 0 |
701 | header->linkname = rawHeader->linkname; | 728 | header->linkname = rawHeader->linkname; |
702 | header->devmajor = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor)); | 729 | header->devmajor = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor)); |
@@ -704,31 +731,58 @@ writeTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) | |||
704 | 731 | ||
705 | /* Write out the checksum */ | 732 | /* Write out the checksum */ |
706 | chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum)); | 733 | chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum)); |
707 | #endif | ||
708 | 734 | ||
709 | return ( TRUE); | 735 | return ( TRUE); |
736 | #endif | ||
710 | } | 737 | } |
711 | 738 | ||
712 | 739 | ||
713 | static int fileAction(const char *fileName, struct stat *statbuf, void* userData) | 740 | static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) |
714 | { | 741 | { |
715 | int *tarFd=(int*)userData; | 742 | int inputFileFd; |
716 | dprintf(*tarFd, "%s\n", fileName); | 743 | struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; |
717 | return (TRUE); | 744 | char header[sizeof(struct TarHeader)]; |
745 | |||
746 | /* First open the file we want to archive, and make sure all is well */ | ||
747 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | ||
748 | errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno)); | ||
749 | return( TRUE); | ||
750 | } | ||
751 | |||
752 | /* It is against the rules to archive a socket */ | ||
753 | if (S_ISSOCK(statbuf->st_mode)) { | ||
754 | errorMsg("tar: %s: socket ignored\n", fileName); | ||
755 | return( TRUE); | ||
756 | } | ||
757 | |||
758 | /* It is a bad idea to store the archive we are in the process of creating, | ||
759 | * so check the device and inode to be sure that this particular file isn't | ||
760 | * the new tarball */ | ||
761 | if (tbInfo->statBuf.st_dev == statbuf->st_dev && | ||
762 | tbInfo->statBuf.st_ino == statbuf->st_ino) { | ||
763 | errorMsg("tar: %s: file is the archive; skipping\n", fileName); | ||
764 | return( TRUE); | ||
765 | } | ||
766 | |||
767 | memset( header, 0, sizeof(struct TarHeader)); | ||
768 | if (writeTarHeader((struct TarHeader *)header, fileName, statbuf)==FALSE) { | ||
769 | dprintf(tbInfo->tarFd, "%s", header); | ||
770 | } | ||
771 | /* Now do the verbose thing (or not) */ | ||
772 | if (tbInfo->verboseFlag==TRUE) | ||
773 | fprintf(stdout, "%s\n", ((struct TarHeader *)header)->name); | ||
774 | |||
775 | return( TRUE); | ||
718 | } | 776 | } |
719 | 777 | ||
720 | static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | 778 | static int writeTarFile(const char* tarName, int tostdoutFlag, |
721 | int tostdoutFlag, int verboseFlag, int argc, char **argv) | 779 | int verboseFlag, int argc, char **argv) |
722 | { | 780 | { |
723 | int tarFd=-1; | 781 | int tarFd=-1; |
724 | //int errorFlag=FALSE; | 782 | int errorFlag=FALSE; |
725 | //TarHeader rawHeader; | ||
726 | //TarInfo header; | ||
727 | //int alreadyWarned=FALSE; | ||
728 | //int skipFileFlag=FALSE; | 783 | //int skipFileFlag=FALSE; |
729 | struct stat tarballStat; | 784 | struct TarBallInfo tbInfo; |
730 | dev_t tarDev = 0; | 785 | tbInfo.verboseFlag = verboseFlag; |
731 | ino_t tarInode = 0; | ||
732 | 786 | ||
733 | /* Make sure there is at least one file to tar up. */ | 787 | /* Make sure there is at least one file to tar up. */ |
734 | if (argc <= 0) | 788 | if (argc <= 0) |
@@ -736,19 +790,17 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | |||
736 | 790 | ||
737 | /* Open the tar file for writing. */ | 791 | /* Open the tar file for writing. */ |
738 | if (tostdoutFlag == TRUE) | 792 | if (tostdoutFlag == TRUE) |
739 | tarFd = fileno(stdout); | 793 | tbInfo.tarFd = fileno(stdout); |
740 | else | 794 | else |
741 | tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); | 795 | tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
742 | if (tarFd < 0) { | 796 | if (tbInfo.tarFd < 0) { |
743 | errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno)); | 797 | errorMsg( "tar: Error opening '%s': %s\n", tarName, strerror(errno)); |
744 | return ( FALSE); | 798 | return ( FALSE); |
745 | } | 799 | } |
746 | /* Store the device and inode of the tarball, so we can be sure | 800 | /* Store the stat info for the tarball's file, so |
747 | * not to try and include it into itself.... */ | 801 | * can avoid including the tarball into itself.... */ |
748 | if (fstat(tarFd, &tarballStat) < 0) | 802 | if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) |
749 | fatalError(io_error, tarName, strerror(errno)); | 803 | fatalError(io_error, tarName, strerror(errno)); |
750 | tarDev = tarballStat.st_dev; | ||
751 | tarInode = tarballStat.st_ino; | ||
752 | 804 | ||
753 | /* Set the umask for this process so it doesn't | 805 | /* Set the umask for this process so it doesn't |
754 | * screw up permission setting for us later. */ | 806 | * screw up permission setting for us later. */ |
@@ -757,12 +809,17 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | |||
757 | /* Read the directory/files and iterate over them one at a time */ | 809 | /* Read the directory/files and iterate over them one at a time */ |
758 | while (argc-- > 0) { | 810 | while (argc-- > 0) { |
759 | if (recursiveAction(*argv++, TRUE, FALSE, FALSE, | 811 | if (recursiveAction(*argv++, TRUE, FALSE, FALSE, |
760 | fileAction, fileAction, (void*) &tarFd) == FALSE) { | 812 | writeFileToTarball, writeFileToTarball, |
761 | exit(FALSE); | 813 | (void*) &tbInfo) == FALSE) { |
814 | errorFlag = TRUE; | ||
762 | } | 815 | } |
763 | } | 816 | } |
764 | 817 | /* Hang up the tools, close up shop, head home */ | |
765 | close(tarFd); | 818 | close(tarFd); |
819 | if (errorFlag == TRUE) { | ||
820 | errorMsg("tar: Error exit delayed from previous errors\n"); | ||
821 | return(FALSE); | ||
822 | } | ||
766 | return( TRUE); | 823 | return( TRUE); |
767 | } | 824 | } |
768 | 825 | ||
@@ -1,12 +1,12 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Mini tar implementation for busybox | ||
3 | * | 4 | * |
4 | * Mini tar implementation for busybox Note, that as of BusyBox 0.43 tar has | 5 | * Note, that as of BusyBox 0.43 tar has been completely rewritten from the |
5 | * been completely rewritten from the ground up. It still has remnents of the | 6 | * ground up. It still has remnents of the old code lying about, but it pretty |
6 | * old code lying about, but it pretty different (i.e. cleaner, less global | 7 | * different (i.e. cleaner, less global variables, etc) |
7 | * variables, etc) | ||
8 | * | 8 | * |
9 | * Copyright (C) 1999 by Lineo, inc. | 9 | * Copyright (C) 2000 by Lineo, inc. |
10 | * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> | 10 | * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> |
11 | * | 11 | * |
12 | * Based in part in the tar implementation in sash | 12 | * Based in part in the tar implementation in sash |
@@ -15,7 +15,7 @@ | |||
15 | * provided that this copyright notice remains intact. | 15 | * provided that this copyright notice remains intact. |
16 | * Permission to distribute sash derived code under the GPL has been granted. | 16 | * Permission to distribute sash derived code under the GPL has been granted. |
17 | * | 17 | * |
18 | * Based in part on the tar implementation in busybox-0.28 | 18 | * Based in part on the tar implementation from busybox-0.28 |
19 | * Copyright (C) 1995 Bruce Perens | 19 | * Copyright (C) 1995 Bruce Perens |
20 | * This is free software under the GNU General Public License. | 20 | * This is free software under the GNU General Public License. |
21 | * | 21 | * |
@@ -162,8 +162,8 @@ static int readTarFile(const char* tarName, int extractFlag, int listFlag, | |||
162 | 162 | ||
163 | #ifdef BB_FEATURE_TAR_CREATE | 163 | #ifdef BB_FEATURE_TAR_CREATE |
164 | /* Local procedures to save files into a tar file. */ | 164 | /* Local procedures to save files into a tar file. */ |
165 | static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | 165 | static int writeTarFile(const char* tarName, int tostdoutFlag, |
166 | int tostdoutFlag, int verboseFlag, int argc, char **argv); | 166 | int verboseFlag, int argc, char **argv); |
167 | static int putOctal(char *cp, int len, long value); | 167 | static int putOctal(char *cp, int len, long value); |
168 | 168 | ||
169 | #endif | 169 | #endif |
@@ -249,7 +249,7 @@ extern int tar_main(int argc, char **argv) | |||
249 | #ifndef BB_FEATURE_TAR_CREATE | 249 | #ifndef BB_FEATURE_TAR_CREATE |
250 | fatalError( "This version of tar was not compiled with tar creation support.\n"); | 250 | fatalError( "This version of tar was not compiled with tar creation support.\n"); |
251 | #else | 251 | #else |
252 | exit(writeTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag, argc, argv)); | 252 | exit(writeTarFile(tarName, tostdoutFlag, verboseFlag, argc, argv)); |
253 | #endif | 253 | #endif |
254 | } else { | 254 | } else { |
255 | exit(readTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag)); | 255 | exit(readTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag)); |
@@ -410,8 +410,6 @@ tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag) | |||
410 | mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)); | 410 | mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)); |
411 | } else if (S_ISFIFO(header->mode)) { | 411 | } else if (S_ISFIFO(header->mode)) { |
412 | mkfifo(header->name, header->mode); | 412 | mkfifo(header->name, header->mode); |
413 | } else { | ||
414 | open(header->name, O_WRONLY | O_CREAT | O_TRUNC, header->mode); | ||
415 | } | 413 | } |
416 | 414 | ||
417 | /* Now set permissions etc for the new directory */ | 415 | /* Now set permissions etc for the new directory */ |
@@ -625,6 +623,21 @@ endgame: | |||
625 | 623 | ||
626 | #ifdef BB_FEATURE_TAR_CREATE | 624 | #ifdef BB_FEATURE_TAR_CREATE |
627 | 625 | ||
626 | /* Some info to be carried along when creating a new tarball */ | ||
627 | struct TarBallInfo | ||
628 | { | ||
629 | char* fileName; /* File name of the tarball */ | ||
630 | int tarFd; /* Open-for-write file descriptor | ||
631 | for the tarball */ | ||
632 | struct stat statBuf; /* Stat info for the tarball, letting | ||
633 | us know the inode and device that the | ||
634 | tarball lives, so we can avoid trying | ||
635 | to include the tarball into itself */ | ||
636 | int verboseFlag; /* Whether to print extra stuff or not */ | ||
637 | }; | ||
638 | typedef struct TarBallInfo TarBallInfo; | ||
639 | |||
640 | |||
628 | /* Put an octal string into the specified buffer. | 641 | /* Put an octal string into the specified buffer. |
629 | * The number is zero and space padded and possibly null padded. | 642 | * The number is zero and space padded and possibly null padded. |
630 | * Returns TRUE if successful. */ | 643 | * Returns TRUE if successful. */ |
@@ -662,41 +675,55 @@ static int putOctal (char *cp, int len, long value) | |||
662 | return TRUE; | 675 | return TRUE; |
663 | } | 676 | } |
664 | 677 | ||
665 | /* Write out a tar header for the specified file */ | 678 | /* Write out a tar header for the specified file/directory/whatever */ |
666 | static int | 679 | static int |
667 | writeTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) | 680 | writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *statbuf) |
668 | { | 681 | { |
669 | int i; | 682 | //int i; |
670 | long chksum, sum; | 683 | //long chksum, sum; |
671 | unsigned char *s = (unsigned char *)rawHeader; | 684 | |
672 | 685 | if (*fileName=='/') { | |
673 | struct TarHeader header; | 686 | static int alreadyWarned=FALSE; |
674 | 687 | if (alreadyWarned==FALSE) { | |
675 | strcpy(header.name, fileName); | 688 | errorMsg("tar: Removing leading '/' from member names\n"); |
676 | putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777); | 689 | alreadyWarned=TRUE; |
677 | putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); | 690 | } |
678 | putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); | 691 | strcpy(header->name, fileName+1); |
679 | putOctal(header.size, sizeof(header.size), statbuf->st_size); | 692 | } |
680 | putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); | 693 | else { |
681 | 694 | strcpy(header->name, fileName); | |
682 | if (S_ISLNK(statbuf.st_mode)) { | 695 | } |
683 | header.type = LNKTYPE; | 696 | putOctal(header->mode, sizeof(header->mode), statbuf->st_mode & 0777); |
684 | // Handle SYMTYPE | 697 | putOctal(header->uid, sizeof(header->uid), statbuf->st_uid); |
685 | } else if (S_ISDIR(statbuf.st_mode)) { | 698 | putOctal(header->gid, sizeof(header->gid), statbuf->st_gid); |
686 | header.type = DIRTYPE; | 699 | putOctal(header->size, sizeof(header->size), statbuf->st_size); |
687 | } else if (S_ISCHR(statbuf.st_mode)) { | 700 | putOctal(header->mtime, sizeof(header->mtime), statbuf->st_mtime); |
688 | header.type = CHRTYPE; | 701 | |
689 | } else if (S_ISBLK(statbuf.st_mode)) { | 702 | if (S_ISLNK(statbuf->st_mode)) { |
690 | header.type = BLKTYPE; | 703 | header->typeflag = LNKTYPE; |
691 | } else if (S_ISFIFO(statbuf.st_mode)) { | 704 | // TODO -- Handle SYMTYPE |
692 | header.type = FIFOTYPE; | 705 | } else if (S_ISDIR(statbuf->st_mode)) { |
693 | } else if (S_ISSOCK(statbuf.st_mode)) { | 706 | header->typeflag = DIRTYPE; |
694 | header.type = S_ISSOCK; | 707 | strncat(header->name, "/", sizeof(header->name)); |
695 | } else if (S_ISLNK(statbuf.st_mode)) { | 708 | } else if (S_ISCHR(statbuf->st_mode)) { |
696 | header.type = LNKTYPE; | 709 | header->typeflag = CHRTYPE; |
697 | } else if (S_ISLNK(statbuf.st_mode)) { | 710 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); |
698 | header.type = REGTYPE; | 711 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); |
712 | } else if (S_ISBLK(statbuf->st_mode)) { | ||
713 | header->typeflag = BLKTYPE; | ||
714 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); | ||
715 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); | ||
716 | } else if (S_ISFIFO(statbuf->st_mode)) { | ||
717 | header->typeflag = FIFOTYPE; | ||
718 | } else if (S_ISLNK(statbuf->st_mode)) { | ||
719 | header->typeflag = LNKTYPE; | ||
720 | } else if (S_ISLNK(statbuf->st_mode)) { | ||
721 | header->typeflag = REGTYPE; | ||
722 | } else { | ||
723 | return ( FALSE); | ||
699 | } | 724 | } |
725 | return ( TRUE); | ||
726 | |||
700 | #if 0 | 727 | #if 0 |
701 | header->linkname = rawHeader->linkname; | 728 | header->linkname = rawHeader->linkname; |
702 | header->devmajor = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor)); | 729 | header->devmajor = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor)); |
@@ -704,31 +731,58 @@ writeTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) | |||
704 | 731 | ||
705 | /* Write out the checksum */ | 732 | /* Write out the checksum */ |
706 | chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum)); | 733 | chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum)); |
707 | #endif | ||
708 | 734 | ||
709 | return ( TRUE); | 735 | return ( TRUE); |
736 | #endif | ||
710 | } | 737 | } |
711 | 738 | ||
712 | 739 | ||
713 | static int fileAction(const char *fileName, struct stat *statbuf, void* userData) | 740 | static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) |
714 | { | 741 | { |
715 | int *tarFd=(int*)userData; | 742 | int inputFileFd; |
716 | dprintf(*tarFd, "%s\n", fileName); | 743 | struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; |
717 | return (TRUE); | 744 | char header[sizeof(struct TarHeader)]; |
745 | |||
746 | /* First open the file we want to archive, and make sure all is well */ | ||
747 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | ||
748 | errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno)); | ||
749 | return( TRUE); | ||
750 | } | ||
751 | |||
752 | /* It is against the rules to archive a socket */ | ||
753 | if (S_ISSOCK(statbuf->st_mode)) { | ||
754 | errorMsg("tar: %s: socket ignored\n", fileName); | ||
755 | return( TRUE); | ||
756 | } | ||
757 | |||
758 | /* It is a bad idea to store the archive we are in the process of creating, | ||
759 | * so check the device and inode to be sure that this particular file isn't | ||
760 | * the new tarball */ | ||
761 | if (tbInfo->statBuf.st_dev == statbuf->st_dev && | ||
762 | tbInfo->statBuf.st_ino == statbuf->st_ino) { | ||
763 | errorMsg("tar: %s: file is the archive; skipping\n", fileName); | ||
764 | return( TRUE); | ||
765 | } | ||
766 | |||
767 | memset( header, 0, sizeof(struct TarHeader)); | ||
768 | if (writeTarHeader((struct TarHeader *)header, fileName, statbuf)==FALSE) { | ||
769 | dprintf(tbInfo->tarFd, "%s", header); | ||
770 | } | ||
771 | /* Now do the verbose thing (or not) */ | ||
772 | if (tbInfo->verboseFlag==TRUE) | ||
773 | fprintf(stdout, "%s\n", ((struct TarHeader *)header)->name); | ||
774 | |||
775 | return( TRUE); | ||
718 | } | 776 | } |
719 | 777 | ||
720 | static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | 778 | static int writeTarFile(const char* tarName, int tostdoutFlag, |
721 | int tostdoutFlag, int verboseFlag, int argc, char **argv) | 779 | int verboseFlag, int argc, char **argv) |
722 | { | 780 | { |
723 | int tarFd=-1; | 781 | int tarFd=-1; |
724 | //int errorFlag=FALSE; | 782 | int errorFlag=FALSE; |
725 | //TarHeader rawHeader; | ||
726 | //TarInfo header; | ||
727 | //int alreadyWarned=FALSE; | ||
728 | //int skipFileFlag=FALSE; | 783 | //int skipFileFlag=FALSE; |
729 | struct stat tarballStat; | 784 | struct TarBallInfo tbInfo; |
730 | dev_t tarDev = 0; | 785 | tbInfo.verboseFlag = verboseFlag; |
731 | ino_t tarInode = 0; | ||
732 | 786 | ||
733 | /* Make sure there is at least one file to tar up. */ | 787 | /* Make sure there is at least one file to tar up. */ |
734 | if (argc <= 0) | 788 | if (argc <= 0) |
@@ -736,19 +790,17 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | |||
736 | 790 | ||
737 | /* Open the tar file for writing. */ | 791 | /* Open the tar file for writing. */ |
738 | if (tostdoutFlag == TRUE) | 792 | if (tostdoutFlag == TRUE) |
739 | tarFd = fileno(stdout); | 793 | tbInfo.tarFd = fileno(stdout); |
740 | else | 794 | else |
741 | tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); | 795 | tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
742 | if (tarFd < 0) { | 796 | if (tbInfo.tarFd < 0) { |
743 | errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno)); | 797 | errorMsg( "tar: Error opening '%s': %s\n", tarName, strerror(errno)); |
744 | return ( FALSE); | 798 | return ( FALSE); |
745 | } | 799 | } |
746 | /* Store the device and inode of the tarball, so we can be sure | 800 | /* Store the stat info for the tarball's file, so |
747 | * not to try and include it into itself.... */ | 801 | * can avoid including the tarball into itself.... */ |
748 | if (fstat(tarFd, &tarballStat) < 0) | 802 | if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) |
749 | fatalError(io_error, tarName, strerror(errno)); | 803 | fatalError(io_error, tarName, strerror(errno)); |
750 | tarDev = tarballStat.st_dev; | ||
751 | tarInode = tarballStat.st_ino; | ||
752 | 804 | ||
753 | /* Set the umask for this process so it doesn't | 805 | /* Set the umask for this process so it doesn't |
754 | * screw up permission setting for us later. */ | 806 | * screw up permission setting for us later. */ |
@@ -757,12 +809,17 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag, | |||
757 | /* Read the directory/files and iterate over them one at a time */ | 809 | /* Read the directory/files and iterate over them one at a time */ |
758 | while (argc-- > 0) { | 810 | while (argc-- > 0) { |
759 | if (recursiveAction(*argv++, TRUE, FALSE, FALSE, | 811 | if (recursiveAction(*argv++, TRUE, FALSE, FALSE, |
760 | fileAction, fileAction, (void*) &tarFd) == FALSE) { | 812 | writeFileToTarball, writeFileToTarball, |
761 | exit(FALSE); | 813 | (void*) &tbInfo) == FALSE) { |
814 | errorFlag = TRUE; | ||
762 | } | 815 | } |
763 | } | 816 | } |
764 | 817 | /* Hang up the tools, close up shop, head home */ | |
765 | close(tarFd); | 818 | close(tarFd); |
819 | if (errorFlag == TRUE) { | ||
820 | errorMsg("tar: Error exit delayed from previous errors\n"); | ||
821 | return(FALSE); | ||
822 | } | ||
766 | return( TRUE); | 823 | return( TRUE); |
767 | } | 824 | } |
768 | 825 | ||