forked from arqbackup/arq_restore
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ArqRepo.m
184 lines (180 loc) · 7 KB
/
ArqRepo.m
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
//
// ArqRepo.m
// Arq
//
// Created by Stefan Reitshamer on 6/23/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "ArqRepo.h"
#import "ArqFark.h"
#import "ArqPackSet.h"
#import "Commit.h"
#import "Tree.h"
#import "NSErrorCodes.h"
#import "ServerBlob.h"
#import "DataInputStream.h"
#import "DecryptedInputStream.h"
#import "NSData-Encrypt.h"
#import "SetNSError.h"
#import "NSError_extra.h"
@implementation ArqRepo
+ (NSString *)errorDomain {
return @"ArqRepoErrorDomain";
}
- (id)initWithS3Service:(S3Service *)theS3
s3BucketName:(NSString *)theS3BucketName
computerUUID:(NSString *)theComputerUUID
bucketUUID:(NSString *)theBucketUUID
encryptionKey:(NSString *)theEncryptionKey {
if (self = [super init]) {
bucketUUID = [theBucketUUID retain];
encryptionKey = [theEncryptionKey retain];
arqFark = [[ArqFark alloc] initWithS3Service:theS3 s3BucketName:theS3BucketName computerUUID:theComputerUUID];
treesPackSet = [[ArqPackSet alloc] initWithS3Service:theS3 s3BucketName:theS3BucketName computerUUID:theComputerUUID packSetName:[theBucketUUID stringByAppendingString:@"-trees"]];
blobsPackSet = [[ArqPackSet alloc] initWithS3Service:theS3 s3BucketName:theS3BucketName computerUUID:theComputerUUID packSetName:[theBucketUUID stringByAppendingString:@"-blobs"]];
}
return self;
}
- (void)dealloc {
[bucketUUID release];
[encryptionKey release];
[arqFark release];
[treesPackSet release];
[blobsPackSet release];
[super dealloc];
}
- (NSString *)headSHA1:(NSError **)error {
NSString *bucketDataPath = [NSString stringWithFormat:@"/%@/refs/heads/master", bucketUUID];
NSError *myError = nil;
NSData *data = [arqFark bucketDataForPath:bucketDataPath error:&myError];
if (data == nil) {
if ([myError isErrorWithDomain:[ArqFark errorDomain] code:ERROR_NOT_FOUND]) {
SETNSERROR([ArqRepo errorDomain], ERROR_NOT_FOUND, @"no head for bucketUUID %@", bucketUUID);
} else {
if (error != NULL) {
*error = myError;
}
}
return nil;
}
return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
}
- (Commit *)commitForSHA1:(NSString *)theSHA1 error:(NSError **)error {
NSError *myError = nil;
ServerBlob *sb = [treesPackSet newServerBlobForSHA1:theSHA1 error:&myError];
if (sb == nil) {
if ([myError isErrorWithDomain:[ArqPackSet errorDomain] code:ERROR_NOT_FOUND]) {
HSLogDebug(@"commit %@ not found in pack set %@", theSHA1, [treesPackSet packSetName]);
SETNSERROR([ArqRepo errorDomain], ERROR_NOT_FOUND, @"commit not found for sha1 %@", theSHA1);
} else {
HSLogError(@"commit not found for %@: %@", theSHA1, [myError localizedDescription]);
if (error != NULL) {
*error = myError;
}
}
return nil;
}
NSData *data = [[sb slurp:error] decryptWithCipher:ARQ_DEFAULT_CIPHER_NAME key:encryptionKey error:error];
[sb release];
if (data == nil) {
return nil;
}
DataInputStream *dis = [[DataInputStream alloc] initWithData:data];
BufferedInputStream *bis = [[BufferedInputStream alloc] initWithUnderlyingStream:dis];
Commit *commit = [[[Commit alloc] initWithBufferedInputStream:bis error:error] autorelease];
[bis release];
[dis release];
return commit;
}
// Returns NO if commit not found:
- (Tree *)treeForSHA1:(NSString *)theSHA1 error:(NSError **)error {
NSError *myError = nil;
ServerBlob *sb = [treesPackSet newServerBlobForSHA1:theSHA1 error:error];
if (sb == nil) {
if ([myError isErrorWithDomain:[ArqPackSet errorDomain] code:ERROR_NOT_FOUND]) {
HSLogDebug(@"tree %@ not found in pack set %@", theSHA1, [treesPackSet packSetName]);
SETNSERROR([ArqRepo errorDomain], ERROR_NOT_FOUND, @"commit not found for sha1 %@", theSHA1);
} else {
HSLogError(@"tree not found for %@: %@", theSHA1, [myError localizedDescription]);
if (error != NULL) {
*error = myError;
}
}
return nil;
}
NSData *data = [[sb slurp:error] decryptWithCipher:ARQ_DEFAULT_CIPHER_NAME key:encryptionKey error:error];
[sb release];
if (data == nil) {
return nil;
}
DataInputStream *dis = [[DataInputStream alloc] initWithData:data];
BufferedInputStream *bis = [[BufferedInputStream alloc] initWithUnderlyingStream:dis];
Tree *tree = [[[Tree alloc] initWithBufferedInputStream:bis error:error] autorelease];
[bis release];
[dis release];
return tree;
}
- (NSData *)blobDataForSHA1:(NSString *)sha1 error:(NSError **)error {
ServerBlob *sb = [self newServerBlobForSHA1:sha1 error:error];
if (sb == nil) {
return nil;
}
NSData *data = [sb slurp:error];
[sb release];
return data;
}
- (NSData *)blobDataForSHA1s:(NSArray *)sha1s error:(NSError **)error {
//FIXME: This is very inefficient!
NSMutableData *ret = [NSMutableData data];
for (NSString *sha1 in sha1s) {
NSData *data = [self blobDataForSHA1:sha1 error:error];
if (data == nil) {
return nil;
}
[ret appendData:data];
}
return ret;
}
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 error:(NSError **)error {
NSError *myError = nil;
ServerBlob *sb = [blobsPackSet newServerBlobForSHA1:sha1 error:&myError];
if (sb == nil) {
if ([myError isErrorWithDomain:[ArqPackSet errorDomain] code:ERROR_NOT_FOUND]) {
HSLogTrace(@"sha1 %@ not found in pack set %@; looking in S3", sha1, [blobsPackSet packSetName]);
sb = [arqFark newServerBlobForSHA1:sha1 error:&myError];
if (sb == nil) {
if ([myError isErrorWithDomain:[ArqFark errorDomain] code:ERROR_NOT_FOUND]) {
SETNSERROR([ArqRepo errorDomain], ERROR_NOT_FOUND, @"sha1 %@ not found", sha1);
} else {
if (error != NULL) {
*error = myError;
}
}
}
} else {
HSLogError(@"error trying to read from pack set: %@", [myError localizedDescription]);
if (error != NULL) {
*error = myError;
}
}
}
if (sb != nil) {
id <InputStream> is = [sb newInputStream];
NSString *mimeType = [sb mimeType];
NSString *downloadName = [sb downloadName];
[sb autorelease];
sb = nil;
DecryptedInputStream *dis = [[DecryptedInputStream alloc] initWithInputStream:is cipherName:ARQ_DEFAULT_CIPHER_NAME key:encryptionKey error:error];
[is release];
if (dis != nil) {
sb = [[ServerBlob alloc] initWithInputStream:dis mimeType:mimeType downloadName:downloadName];
[dis release];
}
}
return sb;
}
#pragma mark NSObject
- (NSString *)description {
return [NSString stringWithFormat:@"<ArqRepo: bucketUUID=%@>", bucketUUID];
}
@end