mirror of
https://github.com/samsonjs/arq_restore.git
synced 2026-03-25 09:25:53 +00:00
121 lines
3.9 KiB
Objective-C
121 lines
3.9 KiB
Objective-C
//
|
|
// PackIndexWriter.m
|
|
// Arq
|
|
//
|
|
// Created by Stefan Reitshamer on 3/3/10.
|
|
// Copyright 2010 __MyCompanyName__. All rights reserved.
|
|
//
|
|
|
|
#import "PackIndexWriter.h"
|
|
#import "DiskPack.h"
|
|
#import "FileInputStream.h"
|
|
#import "FileOutputStream.h"
|
|
#import "IntegerIO.h"
|
|
#import "StringIO.h"
|
|
#import "SetNSError.h"
|
|
#import "SHA1Hash.h"
|
|
#import "NSString_extra.h"
|
|
#import "PackIndexEntry.h"
|
|
#import "BufferedOutputStream.h"
|
|
|
|
@interface PackIndexWriter (internal)
|
|
- (BOOL)appendSHA1:(NSString *)theSHA1 error:(NSError **)error;
|
|
- (BOOL)writeEntries:(NSArray *)entries toStream:(BufferedOutputStream *)bos error:(NSError **)error;
|
|
@end
|
|
|
|
@implementation PackIndexWriter
|
|
- (id)initWithPack:(DiskPack *)theDiskPack destination:(NSString *)theDestination
|
|
targetUID:(uid_t)theTargetUID
|
|
targetGID:(gid_t)theTargetGID {
|
|
if (self = [super init]) {
|
|
diskPack = [theDiskPack retain];
|
|
destination = [theDestination copy];
|
|
targetUID = theTargetUID;
|
|
targetGID = theTargetGID;
|
|
}
|
|
return self;
|
|
}
|
|
- (void)dealloc {
|
|
[diskPack release];
|
|
[destination release];
|
|
[super dealloc];
|
|
}
|
|
- (BOOL)writeIndex:(NSError **)error {
|
|
NSArray *entries = [diskPack sortedPackIndexEntries:error];
|
|
if (entries == nil) {
|
|
return NO;
|
|
}
|
|
BufferedOutputStream *bos = [[BufferedOutputStream alloc] initWithPath:destination targetUID:targetUID targetGID:targetGID append:NO];
|
|
BOOL ret = [self writeEntries:entries toStream:bos error:error];
|
|
if (![bos flush:error]) {
|
|
ret = NO;
|
|
}
|
|
[bos release];
|
|
if (!ret) {
|
|
return NO;
|
|
}
|
|
NSString *indexSHA1 = [SHA1Hash hashFile:destination error:error];
|
|
if (![self appendSHA1:indexSHA1 error:error]) {
|
|
return NO;
|
|
}
|
|
return ret;
|
|
}
|
|
@end
|
|
|
|
@implementation PackIndexWriter (internal)
|
|
- (BOOL)appendSHA1:(NSString *)theSHA1 error:(NSError **)error {
|
|
NSData *sha1Data = [theSHA1 hexStringToData];
|
|
BufferedOutputStream *bos = [[BufferedOutputStream alloc] initWithPath:destination targetUID:targetUID targetGID:targetGID append:YES];
|
|
BOOL ret = [bos writeFully:[sha1Data bytes] length:[sha1Data length] error:error];
|
|
if (![bos flush:error]) {
|
|
ret = NO;
|
|
}
|
|
[bos release];
|
|
return ret;
|
|
}
|
|
- (BOOL)writeEntries:(NSArray *)entries toStream:(BufferedOutputStream *)bos error:(NSError **)error {
|
|
// Write header to index.
|
|
if (![IntegerIO writeUInt32:0xff744f63 to:bos error:error]) { // Magic number.
|
|
return NO;
|
|
}
|
|
if (![IntegerIO writeUInt32:0x00000002 to:bos error:error]) { // Version 2.
|
|
return NO;
|
|
}
|
|
unsigned int firstByte = 0;
|
|
NSUInteger index = 0;
|
|
for (index = 0; index < [entries count]; index++) {
|
|
PackIndexEntry *pie = [entries objectAtIndex:index];
|
|
NSData *sha1Hex = [[pie objectSHA1] hexStringToData];
|
|
unsigned char myFirstByte = ((unsigned char *)[sha1Hex bytes])[0];
|
|
while ((unsigned int)myFirstByte > firstByte) {
|
|
if (![IntegerIO writeUInt32:index to:bos error:error]) {
|
|
return NO;
|
|
}
|
|
firstByte++;
|
|
}
|
|
}
|
|
while (firstByte <= 0xff) {
|
|
if (![IntegerIO writeUInt32:index to:bos error:error]) {
|
|
return NO;
|
|
}
|
|
firstByte++;
|
|
}
|
|
for (index = 0; index < [entries count]; index++) {
|
|
PackIndexEntry *pie = [entries objectAtIndex:index];
|
|
if (![IntegerIO writeUInt64:[pie offset] to:bos error:error]
|
|
|| ![IntegerIO writeUInt64:[pie dataLength] to:bos error:error]) {
|
|
return NO;
|
|
}
|
|
// Write sha1 to index.
|
|
NSData *sha1Data = [[pie objectSHA1] hexStringToData];
|
|
if (![bos writeFully:[sha1Data bytes] length:[sha1Data length] error:error]) {
|
|
break;
|
|
}
|
|
// Write 4 bytes (for alignment) to index.
|
|
if (![IntegerIO writeUInt32:0 to:bos error:error]) {
|
|
return NO;
|
|
}
|
|
}
|
|
return YES;
|
|
}
|
|
@end
|