aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog2
-rw-r--r--applets/usage.c3
-rw-r--r--archival/tar.c97
-rw-r--r--tar.c97
-rw-r--r--usage.c3
5 files changed, 192 insertions, 10 deletions
diff --git a/Changelog b/Changelog
index 83ca4ad87..90212119f 100644
--- a/Changelog
+++ b/Changelog
@@ -43,6 +43,8 @@
43 * Larry Doolittle -- \r handled now in echo and tr 43 * Larry Doolittle -- \r handled now in echo and tr
44 * Matt Kraai -- rewrite of uniq 44 * Matt Kraai -- rewrite of uniq
45 * Mark Whitley -- remix of xargs 45 * Mark Whitley -- remix of xargs
46 * Jim Gleason <jimg@lineo.com> -- fixed tar so it no longer breaks
47 hard links.
46 48
47 49
48 -Erik Andersen 50 -Erik Andersen
diff --git a/applets/usage.c b/applets/usage.c
index bd2321fbc..35d69df42 100644
--- a/applets/usage.c
+++ b/applets/usage.c
@@ -1222,8 +1222,7 @@ const char tar_usage[] =
1222#endif 1222#endif
1223 "[-f tarFile] [FILE(s)] ...\n" 1223 "[-f tarFile] [FILE(s)] ...\n"
1224#ifndef BB_FEATURE_TRIVIAL_HELP 1224#ifndef BB_FEATURE_TRIVIAL_HELP
1225 "\nCreate, extract, or list files from a tar file. Note that\n" 1225 "\nCreate, extract, or list files from a tar file.\n\n"
1226 "this version of tar treats hard links as separate files.\n\n"
1227 "Main operation mode:\n" 1226 "Main operation mode:\n"
1228#ifdef BB_FEATURE_TAR_CREATE 1227#ifdef BB_FEATURE_TAR_CREATE
1229 "\tc\t\tcreate\n" 1228 "\tc\t\tcreate\n"
diff --git a/archival/tar.c b/archival/tar.c
index 7e56fb99a..906fd7eda 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -769,6 +769,21 @@ endgame:
769 769
770#ifdef BB_FEATURE_TAR_CREATE 770#ifdef BB_FEATURE_TAR_CREATE
771 771
772/*
773** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
774** the only functions that deal with the HardLinkInfo structure.
775** Even these functions use the xxxHardLinkInfo() functions.
776*/
777typedef struct HardLinkInfo HardLinkInfo;
778struct HardLinkInfo
779{
780 HardLinkInfo *next; /* Next entry in list */
781 dev_t dev; /* Device number */
782 ino_t ino; /* Inode number */
783 short linkCount; /* (Hard) Link Count */
784 char name[1]; /* Start of filename (must be last) */
785};
786
772/* Some info to be carried along when creating a new tarball */ 787/* Some info to be carried along when creating a new tarball */
773struct TarBallInfo 788struct TarBallInfo
774{ 789{
@@ -781,10 +796,62 @@ struct TarBallInfo
781 to include the tarball into itself */ 796 to include the tarball into itself */
782 int verboseFlag; /* Whether to print extra stuff or not */ 797 int verboseFlag; /* Whether to print extra stuff or not */
783 char** excludeList; /* List of files to not include */ 798 char** excludeList; /* List of files to not include */
799 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
800 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
784}; 801};
785typedef struct TarBallInfo TarBallInfo; 802typedef struct TarBallInfo TarBallInfo;
786 803
787 804
805/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
806static void
807addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
808 short linkCount, const char *name)
809{
810 /* Note: hlInfoHeadPtr can never be NULL! */
811 HardLinkInfo *hlInfo;
812
813 hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
814 if (hlInfo) {
815 hlInfo->next = *hlInfoHeadPtr;
816 *hlInfoHeadPtr = hlInfo;
817 hlInfo->dev = dev;
818 hlInfo->ino = ino;
819 hlInfo->linkCount = linkCount;
820 strcpy(hlInfo->name, name);
821 }
822 return;
823}
824
825static void
826freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
827{
828 HardLinkInfo *hlInfo = NULL;
829 HardLinkInfo *hlInfoNext = NULL;
830
831 if (hlInfoHeadPtr) {
832 hlInfo = *hlInfoHeadPtr;
833 while (hlInfo) {
834 hlInfoNext = hlInfo->next;
835 free(hlInfo);
836 hlInfo = hlInfoNext;
837 }
838 *hlInfoHeadPtr = NULL;
839 }
840 return;
841}
842
843/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
844static HardLinkInfo *
845findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
846{
847 while(hlInfo) {
848 if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
849 break;
850 hlInfo = hlInfo->next;
851 }
852 return(hlInfo);
853}
854
788/* Put an octal string into the specified buffer. 855/* Put an octal string into the specified buffer.
789 * The number is zero and space padded and possibly null padded. 856 * The number is zero and space padded and possibly null padded.
790 * Returns TRUE if successful. */ 857 * Returns TRUE if successful. */
@@ -879,8 +946,11 @@ writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *st
879 if (! *header.uname) 946 if (! *header.uname)
880 strcpy(header.uname, "root"); 947 strcpy(header.uname, "root");
881 948
882 /* WARNING/NOTICE: I break Hard Links */ 949 if (tbInfo->hlInfo) {
883 if (S_ISLNK(statbuf->st_mode)) { 950 /* This is a hard link */
951 header.typeflag = LNKTYPE;
952 strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
953 } else if (S_ISLNK(statbuf->st_mode)) {
884 int link_size=0; 954 int link_size=0;
885 char buffer[BUFSIZ]; 955 char buffer[BUFSIZ];
886 header.typeflag = SYMTYPE; 956 header.typeflag = SYMTYPE;
@@ -948,6 +1018,22 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
948{ 1018{
949 struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; 1019 struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
950 1020
1021 /*
1022 ** Check to see if we are dealing with a hard link.
1023 ** If so -
1024 ** Treat the first occurance of a given dev/inode as a file while
1025 ** treating any additional occurances as hard links. This is done
1026 ** by adding the file information to the HardLinkInfo linked list.
1027 */
1028 tbInfo->hlInfo = NULL;
1029 if (statbuf->st_nlink > 1) {
1030 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev,
1031 statbuf->st_ino);
1032 if (tbInfo->hlInfo == NULL)
1033 addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
1034 statbuf->st_ino, statbuf->st_nlink, fileName);
1035 }
1036
951 /* It is against the rules to archive a socket */ 1037 /* It is against the rules to archive a socket */
952 if (S_ISSOCK(statbuf->st_mode)) { 1038 if (S_ISSOCK(statbuf->st_mode)) {
953 errorMsg("%s: socket ignored\n", fileName); 1039 errorMsg("%s: socket ignored\n", fileName);
@@ -973,7 +1059,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
973 } 1059 }
974 1060
975 /* Now, if the file is a regular file, copy it out to the tarball */ 1061 /* Now, if the file is a regular file, copy it out to the tarball */
976 if (S_ISREG(statbuf->st_mode)) { 1062 if ((tbInfo->hlInfo == NULL)
1063 && (S_ISREG(statbuf->st_mode))) {
977 int inputFileFd; 1064 int inputFileFd;
978 char buffer[BUFSIZ]; 1065 char buffer[BUFSIZ];
979 ssize_t size=0, readSize=0; 1066 ssize_t size=0, readSize=0;
@@ -1015,6 +1102,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
1015 ssize_t size; 1102 ssize_t size;
1016 struct TarBallInfo tbInfo; 1103 struct TarBallInfo tbInfo;
1017 tbInfo.verboseFlag = verboseFlag; 1104 tbInfo.verboseFlag = verboseFlag;
1105 tbInfo.hlInfoHead = NULL;
1018 1106
1019 /* Make sure there is at least one file to tar up. */ 1107 /* Make sure there is at least one file to tar up. */
1020 if (*argv == NULL) 1108 if (*argv == NULL)
@@ -1027,6 +1115,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
1027 tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); 1115 tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1028 if (tbInfo.tarFd < 0) { 1116 if (tbInfo.tarFd < 0) {
1029 errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno)); 1117 errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno));
1118 freeHardLinkInfo(&tbInfo.hlInfoHead);
1030 return ( FALSE); 1119 return ( FALSE);
1031 } 1120 }
1032 tbInfo.excludeList=excludeList; 1121 tbInfo.excludeList=excludeList;
@@ -1061,8 +1150,10 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
1061 close(tarFd); 1150 close(tarFd);
1062 if (errorFlag == TRUE) { 1151 if (errorFlag == TRUE) {
1063 errorMsg("Error exit delayed from previous errors\n"); 1152 errorMsg("Error exit delayed from previous errors\n");
1153 freeHardLinkInfo(&tbInfo.hlInfoHead);
1064 return(FALSE); 1154 return(FALSE);
1065 } 1155 }
1156 freeHardLinkInfo(&tbInfo.hlInfoHead);
1066 return( TRUE); 1157 return( TRUE);
1067} 1158}
1068 1159
diff --git a/tar.c b/tar.c
index 7e56fb99a..906fd7eda 100644
--- a/tar.c
+++ b/tar.c
@@ -769,6 +769,21 @@ endgame:
769 769
770#ifdef BB_FEATURE_TAR_CREATE 770#ifdef BB_FEATURE_TAR_CREATE
771 771
772/*
773** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
774** the only functions that deal with the HardLinkInfo structure.
775** Even these functions use the xxxHardLinkInfo() functions.
776*/
777typedef struct HardLinkInfo HardLinkInfo;
778struct HardLinkInfo
779{
780 HardLinkInfo *next; /* Next entry in list */
781 dev_t dev; /* Device number */
782 ino_t ino; /* Inode number */
783 short linkCount; /* (Hard) Link Count */
784 char name[1]; /* Start of filename (must be last) */
785};
786
772/* Some info to be carried along when creating a new tarball */ 787/* Some info to be carried along when creating a new tarball */
773struct TarBallInfo 788struct TarBallInfo
774{ 789{
@@ -781,10 +796,62 @@ struct TarBallInfo
781 to include the tarball into itself */ 796 to include the tarball into itself */
782 int verboseFlag; /* Whether to print extra stuff or not */ 797 int verboseFlag; /* Whether to print extra stuff or not */
783 char** excludeList; /* List of files to not include */ 798 char** excludeList; /* List of files to not include */
799 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
800 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
784}; 801};
785typedef struct TarBallInfo TarBallInfo; 802typedef struct TarBallInfo TarBallInfo;
786 803
787 804
805/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
806static void
807addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
808 short linkCount, const char *name)
809{
810 /* Note: hlInfoHeadPtr can never be NULL! */
811 HardLinkInfo *hlInfo;
812
813 hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
814 if (hlInfo) {
815 hlInfo->next = *hlInfoHeadPtr;
816 *hlInfoHeadPtr = hlInfo;
817 hlInfo->dev = dev;
818 hlInfo->ino = ino;
819 hlInfo->linkCount = linkCount;
820 strcpy(hlInfo->name, name);
821 }
822 return;
823}
824
825static void
826freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
827{
828 HardLinkInfo *hlInfo = NULL;
829 HardLinkInfo *hlInfoNext = NULL;
830
831 if (hlInfoHeadPtr) {
832 hlInfo = *hlInfoHeadPtr;
833 while (hlInfo) {
834 hlInfoNext = hlInfo->next;
835 free(hlInfo);
836 hlInfo = hlInfoNext;
837 }
838 *hlInfoHeadPtr = NULL;
839 }
840 return;
841}
842
843/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
844static HardLinkInfo *
845findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
846{
847 while(hlInfo) {
848 if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
849 break;
850 hlInfo = hlInfo->next;
851 }
852 return(hlInfo);
853}
854
788/* Put an octal string into the specified buffer. 855/* Put an octal string into the specified buffer.
789 * The number is zero and space padded and possibly null padded. 856 * The number is zero and space padded and possibly null padded.
790 * Returns TRUE if successful. */ 857 * Returns TRUE if successful. */
@@ -879,8 +946,11 @@ writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *st
879 if (! *header.uname) 946 if (! *header.uname)
880 strcpy(header.uname, "root"); 947 strcpy(header.uname, "root");
881 948
882 /* WARNING/NOTICE: I break Hard Links */ 949 if (tbInfo->hlInfo) {
883 if (S_ISLNK(statbuf->st_mode)) { 950 /* This is a hard link */
951 header.typeflag = LNKTYPE;
952 strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
953 } else if (S_ISLNK(statbuf->st_mode)) {
884 int link_size=0; 954 int link_size=0;
885 char buffer[BUFSIZ]; 955 char buffer[BUFSIZ];
886 header.typeflag = SYMTYPE; 956 header.typeflag = SYMTYPE;
@@ -948,6 +1018,22 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
948{ 1018{
949 struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; 1019 struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
950 1020
1021 /*
1022 ** Check to see if we are dealing with a hard link.
1023 ** If so -
1024 ** Treat the first occurance of a given dev/inode as a file while
1025 ** treating any additional occurances as hard links. This is done
1026 ** by adding the file information to the HardLinkInfo linked list.
1027 */
1028 tbInfo->hlInfo = NULL;
1029 if (statbuf->st_nlink > 1) {
1030 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev,
1031 statbuf->st_ino);
1032 if (tbInfo->hlInfo == NULL)
1033 addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
1034 statbuf->st_ino, statbuf->st_nlink, fileName);
1035 }
1036
951 /* It is against the rules to archive a socket */ 1037 /* It is against the rules to archive a socket */
952 if (S_ISSOCK(statbuf->st_mode)) { 1038 if (S_ISSOCK(statbuf->st_mode)) {
953 errorMsg("%s: socket ignored\n", fileName); 1039 errorMsg("%s: socket ignored\n", fileName);
@@ -973,7 +1059,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
973 } 1059 }
974 1060
975 /* Now, if the file is a regular file, copy it out to the tarball */ 1061 /* Now, if the file is a regular file, copy it out to the tarball */
976 if (S_ISREG(statbuf->st_mode)) { 1062 if ((tbInfo->hlInfo == NULL)
1063 && (S_ISREG(statbuf->st_mode))) {
977 int inputFileFd; 1064 int inputFileFd;
978 char buffer[BUFSIZ]; 1065 char buffer[BUFSIZ];
979 ssize_t size=0, readSize=0; 1066 ssize_t size=0, readSize=0;
@@ -1015,6 +1102,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
1015 ssize_t size; 1102 ssize_t size;
1016 struct TarBallInfo tbInfo; 1103 struct TarBallInfo tbInfo;
1017 tbInfo.verboseFlag = verboseFlag; 1104 tbInfo.verboseFlag = verboseFlag;
1105 tbInfo.hlInfoHead = NULL;
1018 1106
1019 /* Make sure there is at least one file to tar up. */ 1107 /* Make sure there is at least one file to tar up. */
1020 if (*argv == NULL) 1108 if (*argv == NULL)
@@ -1027,6 +1115,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
1027 tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); 1115 tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1028 if (tbInfo.tarFd < 0) { 1116 if (tbInfo.tarFd < 0) {
1029 errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno)); 1117 errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno));
1118 freeHardLinkInfo(&tbInfo.hlInfoHead);
1030 return ( FALSE); 1119 return ( FALSE);
1031 } 1120 }
1032 tbInfo.excludeList=excludeList; 1121 tbInfo.excludeList=excludeList;
@@ -1061,8 +1150,10 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
1061 close(tarFd); 1150 close(tarFd);
1062 if (errorFlag == TRUE) { 1151 if (errorFlag == TRUE) {
1063 errorMsg("Error exit delayed from previous errors\n"); 1152 errorMsg("Error exit delayed from previous errors\n");
1153 freeHardLinkInfo(&tbInfo.hlInfoHead);
1064 return(FALSE); 1154 return(FALSE);
1065 } 1155 }
1156 freeHardLinkInfo(&tbInfo.hlInfoHead);
1066 return( TRUE); 1157 return( TRUE);
1067} 1158}
1068 1159
diff --git a/usage.c b/usage.c
index bd2321fbc..35d69df42 100644
--- a/usage.c
+++ b/usage.c
@@ -1222,8 +1222,7 @@ const char tar_usage[] =
1222#endif 1222#endif
1223 "[-f tarFile] [FILE(s)] ...\n" 1223 "[-f tarFile] [FILE(s)] ...\n"
1224#ifndef BB_FEATURE_TRIVIAL_HELP 1224#ifndef BB_FEATURE_TRIVIAL_HELP
1225 "\nCreate, extract, or list files from a tar file. Note that\n" 1225 "\nCreate, extract, or list files from a tar file.\n\n"
1226 "this version of tar treats hard links as separate files.\n\n"
1227 "Main operation mode:\n" 1226 "Main operation mode:\n"
1228#ifdef BB_FEATURE_TAR_CREATE 1227#ifdef BB_FEATURE_TAR_CREATE
1229 "\tc\t\tcreate\n" 1228 "\tc\t\tcreate\n"