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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
|
// Parses tar files, except: Star, sparse tar files.
#import "XADTarParser.h"
#define TAR_FORMAT_V7 0
#define TAR_FORMAT_GNU 1 // GNU and OLDGNU are basically identical
#define TAR_FORMAT_USTAR 2 // POSIX-ish tar formats
#define TAR_FORMAT_STAR 3 // STAR is POSIX-ish, but not similiar enough to ustar and posix.2001 tar.
#define TAR_FORMAT_V7_RECOGNIZED 4
// TODO: star.
@implementation XADTarParser
+(int)requiredHeaderSize { return 512; }
+(int)getTarType:(NSData *)header
{
unsigned char head[512];
[header getBytes:head length:512];
int tarFormat = TAR_FORMAT_V7;
unsigned char magic[8];
[header getBytes:magic range:NSMakeRange(257,8)]; // "ustar\000" (ustar) / "ustar \0" (gnu)
unsigned char starExtendedMagic[4];
[header getBytes:starExtendedMagic range:NSMakeRange(508,4)]; // "tar\0"
unsigned int checksum = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(148,8) buffer:header];
if( [XADTarParser isTarChecksumCorrect:header checksum:checksum] == YES )
{
tarFormat = TAR_FORMAT_V7_RECOGNIZED;
}
if( memcmp( magic, (unsigned char[]){ 117, 115, 116, 97, 114, 0, 48, 48 }, 8 ) == 0 )
{
if( memcmp( starExtendedMagic, (unsigned char[]){ 116, 97, 114, 0 }, 4 ) == 0 )
{
tarFormat = TAR_FORMAT_STAR;
}
else
{
// printf("TAR: Ustar format.\n" );
tarFormat = TAR_FORMAT_USTAR;
}
}
else if( memcmp( magic, (unsigned char[]){ 117, 115, 116, 97, 114, 32, 32, 0 }, 8 ) == 0 )
{
tarFormat = TAR_FORMAT_GNU;
}
return( tarFormat );
}
// Recognize files by name or magic. (tar v7 files have no magic, are recognized as
// TAR_FORMAT_V7_RECOGNIZED via checksums)
+(BOOL)recognizeFileWithHandle:(CSHandle *)handle firstBytes:(NSData *)data name:(NSString *)name
{
if([data length]<512) return NO;
return(
[name matchedByPattern:@"^(.*)\\.tar$" options:REG_ICASE] ||
([XADTarParser getTarType:data] != TAR_FORMAT_V7)
);
}
+(double)doubleFromCString:(char *)buffer
{
NSString *readString = [[NSString alloc] initWithUTF8String:buffer];
NSScanner* scanner = [NSScanner scannerWithString:readString];
[readString release];
double returnValue;
if([scanner scanDouble:&returnValue] == YES) {
return( returnValue );
}
return( 0 );
}
+(int64_t)longFromCString:(char *)buffer
{
NSString *readString = [[NSString alloc] initWithUTF8String:buffer];
NSScanner* scanner = [NSScanner scannerWithString:readString];
[readString release];
long long returnValue;
if([scanner scanLongLong:&returnValue] == YES) {
return( returnValue );
}
return( 0 );
}
+(int64_t)readNumberInRangeFromBuffer:(NSRange)range buffer:(NSData *)buffer
{
NSString *readString = [[NSString alloc] initWithData:[buffer subdataWithRange:range] encoding:NSASCIIStringEncoding];
NSScanner* scanner = [NSScanner scannerWithString:readString];
[readString release];
long long returnValue;
if([scanner scanLongLong:&returnValue] == YES) {
return( returnValue );
}
return( 0 );
}
+(int64_t)octalToDecimal:(int64_t)octal
{
int64_t decimal = 0;
int temp = 0;
int64_t power_of_ten = 10000000000000;
int64_t power_of_eight = 549755813888;
while( power_of_ten != 1 )
{
power_of_ten = power_of_ten / 10;
power_of_eight = power_of_eight / 8;
temp = octal / power_of_ten;
decimal += temp * power_of_eight;
octal -= temp * power_of_ten;
}
return( decimal );
}
+(uint64_t)readOctalNumberInRangeFromBuffer:(NSRange)range buffer:(NSData *)buffer
{
// This implementation only supports numbers up to 2^64. If we ever need bigger numbers,
// that needs to change.
// Also, negative values are not supported. This could be an issue if the mtime field was
// supposed to be negative, but it is probably fair to assume that we will not be
// extracting star archives with files last modified before 1970.
uint8_t num_string[8];
uint8_t mask = 0x80;
[buffer getBytes:num_string range:NSMakeRange(range.location,8)];
if( (num_string[0]&mask) == 0x80 ) {
[buffer getBytes:num_string range:NSMakeRange(range.location + range.length - 8,8)];
return CSUInt64BE(num_string);
}
return( [XADTarParser octalToDecimal:[XADTarParser readNumberInRangeFromBuffer:range buffer:buffer]] );
}
// "Sum of all header bytes if the checksum field was 8 * ' '".
+(BOOL)isTarChecksumCorrect:(NSData *)header checksum:(int)checksum
{
unsigned char head[512];
[header getBytes:head length:512];
int signedChecksum = 0;
unsigned int unsignedChecksum = 0;
for( int i = 0; i < 148; i++ )
{
signedChecksum += (signed char)head[i];
unsignedChecksum += (unsigned char)head[i];
}
for( int i = 156; i < 512; i++ )
{
signedChecksum += (signed char)head[i];
unsignedChecksum += (unsigned char)head[i];
}
signedChecksum += 8 * ' ';
unsignedChecksum += 8 * ' ';
return( checksum == signedChecksum || checksum == unsignedChecksum );
}
-(void)dealloc
{
[currentGlobalHeader release];
[super dealloc];
}
-(void)parseSparseHeadersFromData:(NSData*)header numHeaders:(int)num toDict:(NSMutableDictionary *)dict
{
for( int i = 0; i < num; i++ )
{
off_t regionOffset = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(24*i,12) buffer:header];
off_t regionLength = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(24*i+12,12) buffer:header];
// printf( "Parse sparse header: %d -> %d\n", regionOffset, regionLength );
// Are we done yet?
if( regionLength == 0 && regionOffset == 0 ) {
break;
}
[[dict objectForKey:@"TARSparseRegionOffsets"] addObject:[NSNumber numberWithInt:regionOffset]];
[[dict objectForKey:@"TARSparseRegionLengths"] addObject:[NSNumber numberWithInt:regionLength]];
}
}
-(int)parseGenericTarHeader:(NSData *)header toDict:(NSMutableDictionary *)dict
{
char name[101];
[header getBytes:name range:NSMakeRange(0,100)];
name[100] = '\000';
[dict setObject:[self XADPathWithCString:name separators:XADUnixPathSeparator] forKey:XADFileNameKey];
unsigned int mode = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(100,8) buffer:header];
[dict setObject:[NSNumber numberWithInt:mode] forKey:XADPosixPermissionsKey];
unsigned int uid = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(108,8) buffer:header];
[dict setObject:[NSNumber numberWithInt:uid] forKey:XADPosixUserKey];
unsigned int gid = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(116,8) buffer:header];
[dict setObject:[NSNumber numberWithInt:gid] forKey:XADPosixGroupKey];
uint64_t size = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(124,12) buffer:header];
[dict setObject:[NSNumber numberWithLongLong:size] forKey:XADFileSizeKey];
[dict setObject:[NSNumber numberWithLongLong:(size+(512-size%512))] forKey:XADCompressedSizeKey];
[dict setObject:[NSNumber numberWithLongLong:size] forKey:XADDataLengthKey];
unsigned long mtime = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(136,12) buffer:header];
[dict setObject:[NSDate dateWithTimeIntervalSince1970:mtime] forKey:XADLastModificationDateKey];
unsigned int checksum = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(148,8) buffer:header];
if( [XADTarParser isTarChecksumCorrect:header checksum:checksum] == NO )
{
[XADException raiseIllegalDataException];
}
char typeFlag;
[header getBytes:&typeFlag range:NSMakeRange(156,1)];
// There are only two type flags that tar, in general, supports.
// "Directory"
if( typeFlag == '5' )
{
[dict setObject:[NSNumber numberWithBool:YES] forKey:XADIsDirectoryKey];
}
// "Hard link / soft link"
if( typeFlag == '1' || typeFlag == '2' )
{
char linkName[101];
[header getBytes:linkName range:NSMakeRange(157,100)];
linkName[100] = '\000';
[dict setObject:[self XADStringWithCString:linkName] forKey:XADLinkDestinationKey];
[dict setObject:[NSNumber numberWithInt:(typeFlag%2)] forKey:XADIsHardLinkKey];
}
// KLUDGE: Fix broken directory typeflags.
if( typeFlag == 0 && name[strlen(name)-1] == '/' ) {
[dict setObject:[NSNumber numberWithBool:YES] forKey:XADIsDirectoryKey];
}
// KLUDGE: Fix broken ant tar wrong magic files.
if( strncmp( name, "././@LongLink", 13 ) == 0 ) {
return( 1 );
}
// printf( "Generictar: Name %s / %u\n", name, size );
return( 0 );
}
-(void)parsePaxTarHeader:(NSData *)header toDict:(NSMutableDictionary *)dict {
int position = 0;
while( position < [header length] ) {
// Get next pair length.
int start_pos = position;
int read_length = 0;
char current_char = '\0';
while( current_char != ' ' && read_length < 16 && position < [header length] ) {
[header getBytes:¤t_char range:NSMakeRange(position,1)];
position++;
read_length++;
}
if( read_length == 0 ){
break;
}
// Grab the pair from the header.
int next_pair_size = [XADTarParser readNumberInRangeFromBuffer:NSMakeRange(start_pos,read_length) buffer:header] - read_length;
int next_pair_offset = position + next_pair_size;
char key_val_pair[next_pair_size];
memset( key_val_pair, '\0', next_pair_size );
[header getBytes:key_val_pair range:NSMakeRange(position,next_pair_size - 1)];
// Parse the pair into key/value.
read_length = 0;
start_pos = position;
int max_len = strlen( key_val_pair );
while( key_val_pair[read_length] != '=' && read_length < max_len ) {
position++;
read_length++;
}
char key[read_length + 1];
memcpy( key, key_val_pair, read_length );
key[read_length] = '\0';
char value[max_len - read_length + 1];
memcpy( value, key_val_pair + read_length + 1, (max_len - read_length) );
value[(max_len - read_length)] = '\0';
// Check keys and add proper value to dict.
// Accessed/Created/Last Modified
if( strcmp( key, "atime" ) == 0 ) {
[dict setObject:[NSDate dateWithTimeIntervalSince1970:[XADTarParser doubleFromCString:value]] forKey:XADLastAccessDateKey];
}
else if( strcmp( key, "ctime" ) == 0 ) {
[dict setObject:[NSDate dateWithTimeIntervalSince1970:[XADTarParser doubleFromCString:value]] forKey:XADCreationDateKey];
}
else if( strcmp( key, "mtime" ) == 0 ) {
[dict setObject:[NSDate dateWithTimeIntervalSince1970:[XADTarParser doubleFromCString:value]] forKey:XADLastModificationDateKey];
}
// User/Group ids/names.
else if( strcmp( key, "uname" ) == 0 ) {
[dict setObject:[self XADStringWithCString:value encodingName:XADUTF8StringEncodingName] forKey:XADPosixUserNameKey];
}
else if( strcmp( key, "gname" ) == 0 ) {
[dict setObject:[self XADStringWithCString:value encodingName:XADUTF8StringEncodingName] forKey:XADPosixGroupNameKey];
}
else if( strcmp( key, "uid" ) == 0 ) {
[dict setObject:[NSNumber numberWithInt:[XADTarParser longFromCString:value]] forKey:XADPosixUserKey];
}
else if( strcmp( key, "gid" ) == 0 ) {
[dict setObject:[NSNumber numberWithInt:[XADTarParser longFromCString:value]] forKey:XADPosixGroupKey];
}
// File path and link path.
else if( strcmp( key, "path" ) == 0 ) {
[dict setObject:[self XADPathWithCString:value encodingName:XADUTF8StringEncodingName separators:XADUnixPathSeparator] forKey:XADFileNameKey];
}
else if( strcmp( key, "linkpath" ) == 0 ) {
[dict setObject:[self XADStringWithCString:value encodingName:XADUTF8StringEncodingName] forKey:XADLinkDestinationKey];
}
// File size.
else if( strcmp( key, "size" ) == 0 ) {
[dict setObject:[NSNumber numberWithInt:[XADTarParser longFromCString:value]] forKey:XADFileSizeKey];
}
// Comment.
else if( strcmp( key, "comment" ) == 0 ) {
[dict setObject:[self XADStringWithCString:value encodingName:XADUTF8StringEncodingName] forKey:XADCommentKey];
}
// Continue after the pair.
position = next_pair_offset;
}
}
-(void)parseUstarTarHeader:(NSData *)header toDict:(NSMutableDictionary *)dict
{
char userName[33];
[header getBytes:userName range:NSMakeRange(265,32)];
userName[32] = '\000';
[dict setObject:[self XADStringWithCString:userName] forKey:XADPosixUserNameKey];
char groupName[33];
[header getBytes:groupName range:NSMakeRange(297,32)];
groupName[32] = '\000';
[dict setObject:[self XADStringWithCString:groupName] forKey:XADPosixGroupNameKey];
unsigned int devMajor = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(329,8) buffer:header];
unsigned int devMinor = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(337,8) buffer:header];
char prefix[156];
[header getBytes:prefix range:NSMakeRange(345,155)];
prefix[155] = '\000';
// Prefix is not null => name is prefix . name
char fullName[257];
if( !(prefix[0] == '\000') ) {
char name[101];
[header getBytes:name range:NSMakeRange(0,100)];
name[100] = '\000';
fullName[0] = '\000';
strcat( fullName, prefix );
strcat( fullName, "/" );
strcat( fullName, name );
fullName[256] = '\000';
[dict setObject:[self XADPathWithCString:fullName separators:XADUnixPathSeparator] forKey:XADFileNameKey];
}
char typeFlag;
[header getBytes:&typeFlag range:NSMakeRange(156,1)];
// Global header parse.
[self parsePaxTarHeader:currentGlobalHeader toDict:dict];
// printf( "Ustar header parse after global\n" );
// Needed later for extended headers, possibly.
CSHandle *handle = [self handle];
long size = [[dict objectForKey:XADDataLengthKey] longValue];
off_t offset = [handle offsetInFile];;
offset += size;
offset += (offset % 512 == 0 ? 0 : 512 - (offset % 512) );
switch( typeFlag ) {
// Device files
case '3':
[dict setObject:[NSNumber numberWithInt:1] forKey:XADIsCharacterDeviceKey];
[dict setObject:[NSNumber numberWithInt:devMajor] forKey:XADDeviceMajorKey];
[dict setObject:[NSNumber numberWithInt:devMinor] forKey:XADDeviceMinorKey];
break;
case '4':
[dict setObject:[NSNumber numberWithInt:1] forKey:XADIsBlockDeviceKey];
[dict setObject:[NSNumber numberWithInt:devMajor] forKey:XADDeviceMajorKey];
[dict setObject:[NSNumber numberWithInt:devMinor] forKey:XADDeviceMinorKey];
break;
// FIFOs
case '6':
[dict setObject:[NSNumber numberWithInt:1] forKey:XADIsFIFOKey];
break;
// POSIX.2001 global header.
case 'g': {
// Read in the header and store for parsing
[currentGlobalHeader release];
currentGlobalHeader = [[handle readDataOfLength:size] retain];
[handle seekToFileOffset:offset];
// Parse next header.
NSData *header = [handle readDataOfLength:512];
[dict removeAllObjects];
[self parseGenericTarHeader:header toDict:dict];
[self parseUstarTarHeader:header toDict:dict];
} break;
// POSIX.2001 extended header.
case 'x': {
// Read in the header.
NSData *extendedHeader = [handle readDataOfLength:size];
[handle seekToFileOffset:offset];
// Prepare a new dictionary with the next header.
NSData *header = [handle readDataOfLength:512];
[dict removeAllObjects];
[self parseGenericTarHeader:header toDict:dict];
[self parseUstarTarHeader:header toDict:dict];
// Parse extended header.
[self parsePaxTarHeader:extendedHeader toDict:dict];
} break;
}
}
-(void)parseGnuTarHeader:(NSData *)header toDict:(NSMutableDictionary *)dict
{
char typeFlag;
[header getBytes:&typeFlag range:NSMakeRange(156,1)];
// In case of LongName / LongLink, we need the data.
CSHandle *handle = [self handle];
long size = [[dict objectForKey:XADDataLengthKey] longValue];
off_t offset = [handle offsetInFile];;
offset += size;
offset += (offset % 512 == 0 ? 0 : 512 - (offset % 512) );
// LongName or LongLink?
if( typeFlag == 'L' || typeFlag == 'K' ) {
// Read in the header
NSData *longHeader = [handle readDataOfLength:size];
char longHeaderBytes[size];
memset( longHeaderBytes, '\0', size );
[longHeader getBytes:longHeaderBytes range:NSMakeRange(0,size - 1)];
[handle seekToFileOffset:offset];
// Prepare a new dictionary with the next header.
NSData *header = [handle readDataOfLength:512];
[dict removeAllObjects];
[self parseGenericTarHeader:header toDict:dict];
[self parseGnuTarHeader:header toDict:dict];
// Set the proper key.
if( typeFlag == 'L' ) {
[dict setObject:[self XADPathWithCString:longHeaderBytes separators:XADUnixPathSeparator] forKey:XADFileNameKey];
}
else {
[dict setObject:[self XADStringWithCString:longHeaderBytes] forKey:XADLinkDestinationKey];
}
}
// Sparse header?
if( typeFlag == 'S' ) {
// For now, pass out a "Not supported".
// // Get and store real size.
// off_t size = [XADTarParser readOctalNumberInRangeFromBuffer:NSMakeRange(483,12) buffer:header];
// [dict setObject:[NSNumber numberWithLongLong:size] forKey:XADFileSizeKey];
// [dict setObject:[NSNumber numberWithLongLong:size] forKey:XADDataLengthKey];
//
// // Set up sparse map storage.
[dict setObject:[NSNumber numberWithBool:YES] forKey:@"TARIsSparseFile"];
// [dict setObject:[[NSMutableArray alloc] init] forKey:@"TARSparseRegionOffsets"];
// [dict setObject:[[NSMutableArray alloc] init] forKey:@"TARSparseRegionLengths"];
//
// NSData* sparseMap = [header subdataWithRange:NSMakeRange(386,96)];
// [self parseSparseHeadersFromData:sparseMap numHeaders:4 toDict:dict];
//
// // Handle extended sparse headers.
// char hasExtended;
// [header getBytes:&hasExtended range:NSMakeRange(482,1)];
// printf( "Hasx: %d\n", hasExtended );
// while( hasExtended == 1 ) {
// NSData *sparseMap = [handle readDataOfLength:512];
// [self parseSparseHeadersFromData:sparseMap numHeaders:21 toDict:dict];
// [sparseMap getBytes:&hasExtended range:NSMakeRange(504,1)];
// }
}
}
-(void)addTarEntryWithDictionaryAndSeek:(NSMutableDictionary *)dict
{
CSHandle *handle = [self handle];
off_t size = [[dict objectForKey:XADDataLengthKey] longLongValue];
off_t offset = [handle offsetInFile];
[dict setObject:[NSNumber numberWithLong:offset] forKey:XADDataOffsetKey];
[self addEntryWithDictionary:dict];
offset += size;
offset += (offset % 512 == 0 ? 0 : 512 - (offset % 512) );
[handle seekToFileOffset:offset];
}
-(void)parseWithSeparateMacForks
{
// Reset global current header for posix.2001;
currentGlobalHeader = [NSData new];
CSHandle *handle = [self handle];
int tarFormat = -1;
while([self shouldKeepParsing])
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
// Read next header.
if([handle atEndOfFile]) break;
NSData *header = [handle readDataOfLength:512];
// Figure out format if we haven't yet done so.
if( tarFormat == -1 ) tarFormat = [XADTarParser getTarType:header];
// See if there are 512 nullbytes. That means the file is over.
const char *firstBytes = [header bytes];
BOOL isArchiverOver = YES;
for( int i = 0; i < 512; i++ ) {
if( firstBytes[i] != '\000' ) {
isArchiverOver = NO;
}
}
if( isArchiverOver )
{
[pool release];
break;
}
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
// Reset sparseity.
[dict setObject:[NSNumber numberWithBool:NO] forKey:@"TARIsSparseFile"];
int wrongFormat = [self parseGenericTarHeader:header toDict:dict];
if( wrongFormat == 1 ) {
tarFormat = TAR_FORMAT_GNU;
}
if( tarFormat == TAR_FORMAT_V7 || tarFormat == TAR_FORMAT_V7_RECOGNIZED ) {
[self addTarEntryWithDictionaryAndSeek:dict];
}
else if( tarFormat == TAR_FORMAT_USTAR )
{
[self parseUstarTarHeader:header toDict:dict];
[self addTarEntryWithDictionaryAndSeek:dict];
}
else if( tarFormat == TAR_FORMAT_GNU )
{
[self parseGnuTarHeader:header toDict:dict];
[self addTarEntryWithDictionaryAndSeek:dict];
}
else
{
// Handled like an ustar archive.
[self parseUstarTarHeader:header toDict:dict];
[self addTarEntryWithDictionaryAndSeek:dict];
}
[pool release];
}
}
-(CSHandle *)rawHandleForEntryWithDictionary:(NSDictionary *)dict wantChecksum:(BOOL)checksum
{
CSHandle* retHandle = [self handleAtDataOffsetForDictionary:dict];
if( [[dict objectForKey:@"TARIsSparseFile"] boolValue] ) {
// Just return nil.
return( nil );
// XADTarSparseHandle* sparseHandle = [[XADTarSparseHandle alloc] initWithHandle:retHandle size:[[dict objectForKey:XADDataLengthKey] longValue]];
// NSArray* offsets = [dict objectForKey:@"TARSparseRegionOffsets"];
// NSArray* lengths = [dict objectForKey:@"TARSparseRegionLengths"];
// int sparseRegionCount = [offsets count];
// for( int i = 0; i < sparseRegionCount; i++ ) {
// // GNU tar is pretty special about some things.
// if( [[lengths objectAtIndex:i] longValue] == 0 )
// {
// // The final region is also the first - special case!
// if( i == 0 )
// {
// printf( "Final region add (not really)!\n" );
// [sparseHandle setSingleEmptySparseRegion];
// }
// else
// {
// printf( "Final region add!\n" );
// [sparseHandle addFinalSparseRegionEndingAt:[[offsets objectAtIndex:i] longValue]];
// }
// }
// else
// {
// printf( "Normal region add!\n" );
// [sparseHandle addSparseRegionFrom:[[offsets objectAtIndex:i] longValue] length:[[lengths objectAtIndex:i] longValue]];
// }
// }
// return( sparseHandle );
}
// printf( "Handle return" );
return( retHandle );
}
// This should maybe return USTAR or POSIX Tar or whatever the proper tar type is.
-(NSString *)formatName { return @"Tar"; }
@end
|