Patch from Jim Gleason <jimg@lineo.com> to fix tar so it no longer breaks hard
links, and no longer segfault in a certain wierd case.
This commit is contained in:
parent
6b78fe383f
commit
3d957c87b7
@ -43,6 +43,8 @@
|
|||||||
* Larry Doolittle -- \r handled now in echo and tr
|
* Larry Doolittle -- \r handled now in echo and tr
|
||||||
* Matt Kraai -- rewrite of uniq
|
* Matt Kraai -- rewrite of uniq
|
||||||
* Mark Whitley -- remix of xargs
|
* Mark Whitley -- remix of xargs
|
||||||
|
* Jim Gleason <jimg@lineo.com> -- fixed tar so it no longer breaks
|
||||||
|
hard links.
|
||||||
|
|
||||||
|
|
||||||
-Erik Andersen
|
-Erik Andersen
|
||||||
|
@ -1222,8 +1222,7 @@ const char tar_usage[] =
|
|||||||
#endif
|
#endif
|
||||||
"[-f tarFile] [FILE(s)] ...\n"
|
"[-f tarFile] [FILE(s)] ...\n"
|
||||||
#ifndef BB_FEATURE_TRIVIAL_HELP
|
#ifndef BB_FEATURE_TRIVIAL_HELP
|
||||||
"\nCreate, extract, or list files from a tar file. Note that\n"
|
"\nCreate, extract, or list files from a tar file.\n\n"
|
||||||
"this version of tar treats hard links as separate files.\n\n"
|
|
||||||
"Main operation mode:\n"
|
"Main operation mode:\n"
|
||||||
#ifdef BB_FEATURE_TAR_CREATE
|
#ifdef BB_FEATURE_TAR_CREATE
|
||||||
"\tc\t\tcreate\n"
|
"\tc\t\tcreate\n"
|
||||||
|
@ -769,6 +769,21 @@ endgame:
|
|||||||
|
|
||||||
#ifdef BB_FEATURE_TAR_CREATE
|
#ifdef BB_FEATURE_TAR_CREATE
|
||||||
|
|
||||||
|
/*
|
||||||
|
** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
|
||||||
|
** the only functions that deal with the HardLinkInfo structure.
|
||||||
|
** Even these functions use the xxxHardLinkInfo() functions.
|
||||||
|
*/
|
||||||
|
typedef struct HardLinkInfo HardLinkInfo;
|
||||||
|
struct HardLinkInfo
|
||||||
|
{
|
||||||
|
HardLinkInfo *next; /* Next entry in list */
|
||||||
|
dev_t dev; /* Device number */
|
||||||
|
ino_t ino; /* Inode number */
|
||||||
|
short linkCount; /* (Hard) Link Count */
|
||||||
|
char name[1]; /* Start of filename (must be last) */
|
||||||
|
};
|
||||||
|
|
||||||
/* Some info to be carried along when creating a new tarball */
|
/* Some info to be carried along when creating a new tarball */
|
||||||
struct TarBallInfo
|
struct TarBallInfo
|
||||||
{
|
{
|
||||||
@ -781,10 +796,62 @@ struct TarBallInfo
|
|||||||
to include the tarball into itself */
|
to include the tarball into itself */
|
||||||
int verboseFlag; /* Whether to print extra stuff or not */
|
int verboseFlag; /* Whether to print extra stuff or not */
|
||||||
char** excludeList; /* List of files to not include */
|
char** excludeList; /* List of files to not include */
|
||||||
|
HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
|
||||||
|
HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
|
||||||
};
|
};
|
||||||
typedef struct TarBallInfo TarBallInfo;
|
typedef struct TarBallInfo TarBallInfo;
|
||||||
|
|
||||||
|
|
||||||
|
/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
|
||||||
|
static void
|
||||||
|
addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
|
||||||
|
short linkCount, const char *name)
|
||||||
|
{
|
||||||
|
/* Note: hlInfoHeadPtr can never be NULL! */
|
||||||
|
HardLinkInfo *hlInfo;
|
||||||
|
|
||||||
|
hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
|
||||||
|
if (hlInfo) {
|
||||||
|
hlInfo->next = *hlInfoHeadPtr;
|
||||||
|
*hlInfoHeadPtr = hlInfo;
|
||||||
|
hlInfo->dev = dev;
|
||||||
|
hlInfo->ino = ino;
|
||||||
|
hlInfo->linkCount = linkCount;
|
||||||
|
strcpy(hlInfo->name, name);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
|
||||||
|
{
|
||||||
|
HardLinkInfo *hlInfo = NULL;
|
||||||
|
HardLinkInfo *hlInfoNext = NULL;
|
||||||
|
|
||||||
|
if (hlInfoHeadPtr) {
|
||||||
|
hlInfo = *hlInfoHeadPtr;
|
||||||
|
while (hlInfo) {
|
||||||
|
hlInfoNext = hlInfo->next;
|
||||||
|
free(hlInfo);
|
||||||
|
hlInfo = hlInfoNext;
|
||||||
|
}
|
||||||
|
*hlInfoHeadPtr = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
|
||||||
|
static HardLinkInfo *
|
||||||
|
findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
|
||||||
|
{
|
||||||
|
while(hlInfo) {
|
||||||
|
if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
|
||||||
|
break;
|
||||||
|
hlInfo = hlInfo->next;
|
||||||
|
}
|
||||||
|
return(hlInfo);
|
||||||
|
}
|
||||||
|
|
||||||
/* Put an octal string into the specified buffer.
|
/* Put an octal string into the specified buffer.
|
||||||
* The number is zero and space padded and possibly null padded.
|
* The number is zero and space padded and possibly null padded.
|
||||||
* Returns TRUE if successful. */
|
* Returns TRUE if successful. */
|
||||||
@ -879,8 +946,11 @@ writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *st
|
|||||||
if (! *header.uname)
|
if (! *header.uname)
|
||||||
strcpy(header.uname, "root");
|
strcpy(header.uname, "root");
|
||||||
|
|
||||||
/* WARNING/NOTICE: I break Hard Links */
|
if (tbInfo->hlInfo) {
|
||||||
if (S_ISLNK(statbuf->st_mode)) {
|
/* This is a hard link */
|
||||||
|
header.typeflag = LNKTYPE;
|
||||||
|
strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
|
||||||
|
} else if (S_ISLNK(statbuf->st_mode)) {
|
||||||
int link_size=0;
|
int link_size=0;
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
header.typeflag = SYMTYPE;
|
header.typeflag = SYMTYPE;
|
||||||
@ -948,6 +1018,22 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
|
|||||||
{
|
{
|
||||||
struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
|
struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check to see if we are dealing with a hard link.
|
||||||
|
** If so -
|
||||||
|
** Treat the first occurance of a given dev/inode as a file while
|
||||||
|
** treating any additional occurances as hard links. This is done
|
||||||
|
** by adding the file information to the HardLinkInfo linked list.
|
||||||
|
*/
|
||||||
|
tbInfo->hlInfo = NULL;
|
||||||
|
if (statbuf->st_nlink > 1) {
|
||||||
|
tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev,
|
||||||
|
statbuf->st_ino);
|
||||||
|
if (tbInfo->hlInfo == NULL)
|
||||||
|
addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
|
||||||
|
statbuf->st_ino, statbuf->st_nlink, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
/* It is against the rules to archive a socket */
|
/* It is against the rules to archive a socket */
|
||||||
if (S_ISSOCK(statbuf->st_mode)) {
|
if (S_ISSOCK(statbuf->st_mode)) {
|
||||||
errorMsg("%s: socket ignored\n", fileName);
|
errorMsg("%s: socket ignored\n", fileName);
|
||||||
@ -973,7 +1059,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now, if the file is a regular file, copy it out to the tarball */
|
/* Now, if the file is a regular file, copy it out to the tarball */
|
||||||
if (S_ISREG(statbuf->st_mode)) {
|
if ((tbInfo->hlInfo == NULL)
|
||||||
|
&& (S_ISREG(statbuf->st_mode))) {
|
||||||
int inputFileFd;
|
int inputFileFd;
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
ssize_t size=0, readSize=0;
|
ssize_t size=0, readSize=0;
|
||||||
@ -1015,6 +1102,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
|
|||||||
ssize_t size;
|
ssize_t size;
|
||||||
struct TarBallInfo tbInfo;
|
struct TarBallInfo tbInfo;
|
||||||
tbInfo.verboseFlag = verboseFlag;
|
tbInfo.verboseFlag = verboseFlag;
|
||||||
|
tbInfo.hlInfoHead = NULL;
|
||||||
|
|
||||||
/* Make sure there is at least one file to tar up. */
|
/* Make sure there is at least one file to tar up. */
|
||||||
if (*argv == NULL)
|
if (*argv == NULL)
|
||||||
@ -1027,6 +1115,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
|
|||||||
tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if (tbInfo.tarFd < 0) {
|
if (tbInfo.tarFd < 0) {
|
||||||
errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno));
|
errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno));
|
||||||
|
freeHardLinkInfo(&tbInfo.hlInfoHead);
|
||||||
return ( FALSE);
|
return ( FALSE);
|
||||||
}
|
}
|
||||||
tbInfo.excludeList=excludeList;
|
tbInfo.excludeList=excludeList;
|
||||||
@ -1061,8 +1150,10 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
|
|||||||
close(tarFd);
|
close(tarFd);
|
||||||
if (errorFlag == TRUE) {
|
if (errorFlag == TRUE) {
|
||||||
errorMsg("Error exit delayed from previous errors\n");
|
errorMsg("Error exit delayed from previous errors\n");
|
||||||
|
freeHardLinkInfo(&tbInfo.hlInfoHead);
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
freeHardLinkInfo(&tbInfo.hlInfoHead);
|
||||||
return( TRUE);
|
return( TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
97
tar.c
97
tar.c
@ -769,6 +769,21 @@ endgame:
|
|||||||
|
|
||||||
#ifdef BB_FEATURE_TAR_CREATE
|
#ifdef BB_FEATURE_TAR_CREATE
|
||||||
|
|
||||||
|
/*
|
||||||
|
** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
|
||||||
|
** the only functions that deal with the HardLinkInfo structure.
|
||||||
|
** Even these functions use the xxxHardLinkInfo() functions.
|
||||||
|
*/
|
||||||
|
typedef struct HardLinkInfo HardLinkInfo;
|
||||||
|
struct HardLinkInfo
|
||||||
|
{
|
||||||
|
HardLinkInfo *next; /* Next entry in list */
|
||||||
|
dev_t dev; /* Device number */
|
||||||
|
ino_t ino; /* Inode number */
|
||||||
|
short linkCount; /* (Hard) Link Count */
|
||||||
|
char name[1]; /* Start of filename (must be last) */
|
||||||
|
};
|
||||||
|
|
||||||
/* Some info to be carried along when creating a new tarball */
|
/* Some info to be carried along when creating a new tarball */
|
||||||
struct TarBallInfo
|
struct TarBallInfo
|
||||||
{
|
{
|
||||||
@ -781,10 +796,62 @@ struct TarBallInfo
|
|||||||
to include the tarball into itself */
|
to include the tarball into itself */
|
||||||
int verboseFlag; /* Whether to print extra stuff or not */
|
int verboseFlag; /* Whether to print extra stuff or not */
|
||||||
char** excludeList; /* List of files to not include */
|
char** excludeList; /* List of files to not include */
|
||||||
|
HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
|
||||||
|
HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
|
||||||
};
|
};
|
||||||
typedef struct TarBallInfo TarBallInfo;
|
typedef struct TarBallInfo TarBallInfo;
|
||||||
|
|
||||||
|
|
||||||
|
/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
|
||||||
|
static void
|
||||||
|
addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
|
||||||
|
short linkCount, const char *name)
|
||||||
|
{
|
||||||
|
/* Note: hlInfoHeadPtr can never be NULL! */
|
||||||
|
HardLinkInfo *hlInfo;
|
||||||
|
|
||||||
|
hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
|
||||||
|
if (hlInfo) {
|
||||||
|
hlInfo->next = *hlInfoHeadPtr;
|
||||||
|
*hlInfoHeadPtr = hlInfo;
|
||||||
|
hlInfo->dev = dev;
|
||||||
|
hlInfo->ino = ino;
|
||||||
|
hlInfo->linkCount = linkCount;
|
||||||
|
strcpy(hlInfo->name, name);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
|
||||||
|
{
|
||||||
|
HardLinkInfo *hlInfo = NULL;
|
||||||
|
HardLinkInfo *hlInfoNext = NULL;
|
||||||
|
|
||||||
|
if (hlInfoHeadPtr) {
|
||||||
|
hlInfo = *hlInfoHeadPtr;
|
||||||
|
while (hlInfo) {
|
||||||
|
hlInfoNext = hlInfo->next;
|
||||||
|
free(hlInfo);
|
||||||
|
hlInfo = hlInfoNext;
|
||||||
|
}
|
||||||
|
*hlInfoHeadPtr = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
|
||||||
|
static HardLinkInfo *
|
||||||
|
findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
|
||||||
|
{
|
||||||
|
while(hlInfo) {
|
||||||
|
if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
|
||||||
|
break;
|
||||||
|
hlInfo = hlInfo->next;
|
||||||
|
}
|
||||||
|
return(hlInfo);
|
||||||
|
}
|
||||||
|
|
||||||
/* Put an octal string into the specified buffer.
|
/* Put an octal string into the specified buffer.
|
||||||
* The number is zero and space padded and possibly null padded.
|
* The number is zero and space padded and possibly null padded.
|
||||||
* Returns TRUE if successful. */
|
* Returns TRUE if successful. */
|
||||||
@ -879,8 +946,11 @@ writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *st
|
|||||||
if (! *header.uname)
|
if (! *header.uname)
|
||||||
strcpy(header.uname, "root");
|
strcpy(header.uname, "root");
|
||||||
|
|
||||||
/* WARNING/NOTICE: I break Hard Links */
|
if (tbInfo->hlInfo) {
|
||||||
if (S_ISLNK(statbuf->st_mode)) {
|
/* This is a hard link */
|
||||||
|
header.typeflag = LNKTYPE;
|
||||||
|
strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
|
||||||
|
} else if (S_ISLNK(statbuf->st_mode)) {
|
||||||
int link_size=0;
|
int link_size=0;
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
header.typeflag = SYMTYPE;
|
header.typeflag = SYMTYPE;
|
||||||
@ -948,6 +1018,22 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
|
|||||||
{
|
{
|
||||||
struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
|
struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check to see if we are dealing with a hard link.
|
||||||
|
** If so -
|
||||||
|
** Treat the first occurance of a given dev/inode as a file while
|
||||||
|
** treating any additional occurances as hard links. This is done
|
||||||
|
** by adding the file information to the HardLinkInfo linked list.
|
||||||
|
*/
|
||||||
|
tbInfo->hlInfo = NULL;
|
||||||
|
if (statbuf->st_nlink > 1) {
|
||||||
|
tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev,
|
||||||
|
statbuf->st_ino);
|
||||||
|
if (tbInfo->hlInfo == NULL)
|
||||||
|
addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
|
||||||
|
statbuf->st_ino, statbuf->st_nlink, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
/* It is against the rules to archive a socket */
|
/* It is against the rules to archive a socket */
|
||||||
if (S_ISSOCK(statbuf->st_mode)) {
|
if (S_ISSOCK(statbuf->st_mode)) {
|
||||||
errorMsg("%s: socket ignored\n", fileName);
|
errorMsg("%s: socket ignored\n", fileName);
|
||||||
@ -973,7 +1059,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now, if the file is a regular file, copy it out to the tarball */
|
/* Now, if the file is a regular file, copy it out to the tarball */
|
||||||
if (S_ISREG(statbuf->st_mode)) {
|
if ((tbInfo->hlInfo == NULL)
|
||||||
|
&& (S_ISREG(statbuf->st_mode))) {
|
||||||
int inputFileFd;
|
int inputFileFd;
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
ssize_t size=0, readSize=0;
|
ssize_t size=0, readSize=0;
|
||||||
@ -1015,6 +1102,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
|
|||||||
ssize_t size;
|
ssize_t size;
|
||||||
struct TarBallInfo tbInfo;
|
struct TarBallInfo tbInfo;
|
||||||
tbInfo.verboseFlag = verboseFlag;
|
tbInfo.verboseFlag = verboseFlag;
|
||||||
|
tbInfo.hlInfoHead = NULL;
|
||||||
|
|
||||||
/* Make sure there is at least one file to tar up. */
|
/* Make sure there is at least one file to tar up. */
|
||||||
if (*argv == NULL)
|
if (*argv == NULL)
|
||||||
@ -1027,6 +1115,7 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
|
|||||||
tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if (tbInfo.tarFd < 0) {
|
if (tbInfo.tarFd < 0) {
|
||||||
errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno));
|
errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno));
|
||||||
|
freeHardLinkInfo(&tbInfo.hlInfoHead);
|
||||||
return ( FALSE);
|
return ( FALSE);
|
||||||
}
|
}
|
||||||
tbInfo.excludeList=excludeList;
|
tbInfo.excludeList=excludeList;
|
||||||
@ -1061,8 +1150,10 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
|
|||||||
close(tarFd);
|
close(tarFd);
|
||||||
if (errorFlag == TRUE) {
|
if (errorFlag == TRUE) {
|
||||||
errorMsg("Error exit delayed from previous errors\n");
|
errorMsg("Error exit delayed from previous errors\n");
|
||||||
|
freeHardLinkInfo(&tbInfo.hlInfoHead);
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
freeHardLinkInfo(&tbInfo.hlInfoHead);
|
||||||
return( TRUE);
|
return( TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
usage.c
3
usage.c
@ -1222,8 +1222,7 @@ const char tar_usage[] =
|
|||||||
#endif
|
#endif
|
||||||
"[-f tarFile] [FILE(s)] ...\n"
|
"[-f tarFile] [FILE(s)] ...\n"
|
||||||
#ifndef BB_FEATURE_TRIVIAL_HELP
|
#ifndef BB_FEATURE_TRIVIAL_HELP
|
||||||
"\nCreate, extract, or list files from a tar file. Note that\n"
|
"\nCreate, extract, or list files from a tar file.\n\n"
|
||||||
"this version of tar treats hard links as separate files.\n\n"
|
|
||||||
"Main operation mode:\n"
|
"Main operation mode:\n"
|
||||||
#ifdef BB_FEATURE_TAR_CREATE
|
#ifdef BB_FEATURE_TAR_CREATE
|
||||||
"\tc\t\tcreate\n"
|
"\tc\t\tcreate\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user