1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/*
* Functions for extracting tar archives.
* Bruce Perens, April-May 1995
* Copyright (C) 1995 Bruce Perens
* This is free software under the GNU General Public License.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <tarfn.h>
struct TarHeader {
char Name[100];
char Mode[8];
char UserID[8];
char GroupID[8];
char Size[12];
char ModificationTime[12];
char Checksum[8];
char LinkFlag;
char LinkName[100];
char MagicNumber[8];
char UserName[32];
char GroupName[32];
char MajorDevice[8];
char MinorDevice[8];
};
typedef struct TarHeader TarHeader;
static const unsigned int TarChecksumOffset
= (unsigned int)&(((TarHeader *)0)->Checksum);
/* Octal-ASCII-to-long */
static long
OtoL(const char * s, int size)
{
int n = 0;
while ( *s == ' ' ) {
s++;
size--;
}
while ( --size >= 0 && *s >= '0' && *s <= '7' )
n = (n * 010) + (*s++ - '0');
return n;
}
static int
DecodeTarHeader(char * block, TarInfo * d)
{
TarHeader * h = (TarHeader *)block;
unsigned char * s = (unsigned char *)block;
struct passwd * passwd = 0;
struct group * group = 0;
unsigned int i;
long sum;
long checksum;
if ( *h->UserName )
passwd = getpwnam(h->UserName);
if ( *h->GroupName )
group = getgrnam(h->GroupName);
d->Name = h->Name;
d->LinkName = h->LinkName;
d->Mode = (mode_t)OtoL(h->Mode, sizeof(h->Mode));
d->Size = (size_t)OtoL(h->Size, sizeof(h->Size));
d->ModTime = (time_t)OtoL(h->ModificationTime
,sizeof(h->ModificationTime));
d->Device = ((OtoL(h->MajorDevice, sizeof(h->MajorDevice)) & 0xff) << 8)
| (OtoL(h->MinorDevice, sizeof(h->MinorDevice)) & 0xff);
checksum = OtoL(h->Checksum, sizeof(h->Checksum));
d->UserID = (uid_t)OtoL(h->UserID, sizeof(h->UserID));
d->GroupID = (gid_t)OtoL(h->GroupID, sizeof(h->GroupID));
d->Type = (TarFileType)h->LinkFlag;
if ( passwd )
d->UserID = passwd->pw_uid;
if ( group )
d->GroupID = group->gr_gid;
sum = ' ' * sizeof(h->Checksum);/* Treat checksum field as all blank */
for ( i = TarChecksumOffset; i > 0; i-- )
sum += *s++;
s += sizeof(h->Checksum); /* Skip the real checksum field */
for ( i = (512 - TarChecksumOffset - sizeof(h->Checksum)); i > 0; i-- )
sum += *s++;
return ( sum == checksum );
}
extern int
TarExtractor(
void * userData
,const TarFunctions * functions)
{
int status;
char buffer[512];
TarInfo h;
h.UserData = userData;
while ( (status = functions->Read(userData, buffer, 512)) == 512 ) {
int nameLength;
if ( !DecodeTarHeader(buffer, &h) ) {
if ( h.Name[0] == '\0' ) {
return 0; /* End of tape */
} else {
errno = 0; /* Indicates broken tarfile */
return -1; /* Header checksum error */
}
}
if ( h.Name[0] == '\0' ) {
errno = 0; /* Indicates broken tarfile */
return -1; /* Bad header data */
}
nameLength = strlen(h.Name);
switch ( h.Type ) {
case NormalFile0:
case NormalFile1:
/* Compatibility with pre-ANSI ustar */
if ( h.Name[nameLength - 1] != '/' ) {
status = (*functions->ExtractFile)(&h);
break;
}
/* Else, Fall Through */
case Directory:
h.Name[nameLength - 1] = '\0';
status = (*functions->MakeDirectory)(&h);
break;
case HardLink:
status = (*functions->MakeHardLink)(&h);
break;
case SymbolicLink:
status = (*functions->MakeSymbolicLink)(&h);
break;
case CharacterDevice:
case BlockDevice:
case FIFO:
status = (*functions->MakeSpecialFile)(&h);
break;
default:
errno = 0; /* Indicates broken tarfile */
return -1; /* Bad header field */
}
if ( status != 0 )
return status; /* Pass on status from coroutine */
}
if ( status > 0 ) { /* Read partial header record */
errno = 0; /* Indicates broken tarfile */
return -1;
} else {
return status; /* Whatever I/O function returned */
}
}
|