mirror of
https://github.com/samsonjs/arq_restore.git
synced 2026-03-25 09:25:53 +00:00
194 lines
7 KiB
Objective-C
194 lines
7 KiB
Objective-C
//
|
|
// ArqVerifyCommand.m
|
|
// arq_restore
|
|
//
|
|
// Created by Stefan Reitshamer on 6/17/10.
|
|
// Copyright 2010 __MyCompanyName__. All rights reserved.
|
|
//
|
|
|
|
#import "ArqVerifyCommand.h"
|
|
#import "S3AuthorizationProvider.h"
|
|
#import "S3Service.h"
|
|
#import "HTTP.h"
|
|
#import "RegexKitLite.h"
|
|
#import "BucketVerifier.h"
|
|
#import "NSError_extra.h"
|
|
#import "NSErrorCodes.h"
|
|
#import "ArqSalt.h"
|
|
#import "ArqRepo.h"
|
|
|
|
@interface ArqVerifyCommand (internal)
|
|
- (BOOL)loadObjectSHA1sForS3BucketName:(NSString *)s3BucketName computerUUID:(NSString *)computerUUID error:(NSError **)error;
|
|
@end
|
|
|
|
@implementation ArqVerifyCommand
|
|
- (id)initWithAccessKey:(NSString *)theAccessKey secretKey:(NSString *)theSecretKey encryptionPassword:(NSString *)theEncryptionPassword {
|
|
if (self = [super init]) {
|
|
accessKey = [theAccessKey retain];
|
|
secretKey = [theSecretKey retain];
|
|
encryptionPassword = [theEncryptionPassword retain];
|
|
S3AuthorizationProvider *sap = [[S3AuthorizationProvider alloc] initWithAccessKey:accessKey secretKey:secretKey];
|
|
s3 = [[S3Service alloc] initWithS3AuthorizationProvider:sap useSSL:NO retryOnTransientError:YES];
|
|
[sap release];
|
|
}
|
|
return self;
|
|
}
|
|
- (void)dealloc {
|
|
[accessKey release];
|
|
[secretKey release];
|
|
[encryptionPassword release];
|
|
[s3 release];
|
|
[super dealloc];
|
|
}
|
|
- (void)setVerbose:(BOOL)isVerbose {
|
|
verbose = isVerbose;
|
|
}
|
|
- (BOOL)verifyAll:(NSError **)error {
|
|
NSArray *s3BucketNames = [S3Service s3BucketNamesForAccessKeyID:accessKey];
|
|
for (NSString *s3BucketName in s3BucketNames) {
|
|
printf("s3bucket name: %s\n", [s3BucketName UTF8String]);
|
|
}
|
|
for (NSString *s3BucketName in s3BucketNames) {
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
BOOL ret = [self verifyS3BucketName:s3BucketName error:error];
|
|
if (error != NULL) {
|
|
[*error retain];
|
|
}
|
|
[pool drain];
|
|
if (error != NULL) {
|
|
[*error autorelease];
|
|
}
|
|
if (!ret) {
|
|
return NO;
|
|
}
|
|
}
|
|
return YES;
|
|
}
|
|
- (BOOL)verifyS3BucketName:(NSString *)s3BucketName error:(NSError **)error {
|
|
printf("verifying s3Bucket %s\n", [s3BucketName UTF8String]);
|
|
NSString *computerUUIDPrefix = [NSString stringWithFormat:@"/%@/", s3BucketName];
|
|
NSError *myError = nil;
|
|
NSArray *computerUUIDs = [s3 commonPrefixesForPathPrefix:computerUUIDPrefix delimiter:@"/" error:&myError];
|
|
if (computerUUIDs == nil) {
|
|
if ([myError isErrorWithDomain:[S3Service errorDomain] code:ERROR_NOT_FOUND]) {
|
|
// Skip.
|
|
printf("no computer UUIDs found in bucket %s\n", [s3BucketName UTF8String]);
|
|
return YES;
|
|
} else {
|
|
if (error != NULL) {
|
|
*error = myError;
|
|
}
|
|
return NO;
|
|
}
|
|
}
|
|
for (NSString *computerUUID in computerUUIDs) {
|
|
printf("found computer UUID %s\n", [computerUUID UTF8String]);
|
|
}
|
|
for (NSString *computerUUID in computerUUIDs) {
|
|
if (![self verifyS3BucketName:s3BucketName computerUUID:computerUUID error:error]) {
|
|
return NO;
|
|
}
|
|
}
|
|
return YES;
|
|
}
|
|
- (BOOL)verifyS3BucketName:(NSString *)s3BucketName computerUUID:(NSString *)computerUUID error:(NSError **)error {
|
|
printf("\nverifying computerUUID %s s3Bucket %s\n", [computerUUID UTF8String], [s3BucketName UTF8String]);
|
|
NSString *computerBucketsPrefix = [NSString stringWithFormat:@"/%@/%@/buckets", s3BucketName, computerUUID];
|
|
NSArray *s3BucketUUIDPaths = [s3 pathsWithPrefix:computerBucketsPrefix error:error];
|
|
if (s3BucketUUIDPaths == nil) {
|
|
return NO;
|
|
}
|
|
|
|
NSMutableArray *bucketUUIDs = [NSMutableArray array];
|
|
for (NSString *s3BucketUUIDPath in s3BucketUUIDPaths) {
|
|
NSString *bucketUUID = [s3BucketUUIDPath lastPathComponent];
|
|
printf("found bucket UUID %s\n", [bucketUUID UTF8String]);
|
|
[bucketUUIDs addObject:bucketUUID];
|
|
}
|
|
|
|
[objectSHA1s release];
|
|
objectSHA1s = nil;
|
|
if (![self loadObjectSHA1sForS3BucketName:s3BucketName computerUUID:computerUUID error:error]) {
|
|
return NO;
|
|
}
|
|
|
|
BOOL ret = YES;
|
|
NSAutoreleasePool *pool = nil;
|
|
for (NSString *bucketUUID in bucketUUIDs) {
|
|
[pool release];
|
|
pool = [[NSAutoreleasePool alloc] init];
|
|
if (![self verifyS3BucketName:s3BucketName computerUUID:computerUUID bucketUUID:bucketUUID error:error]) {
|
|
ret = NO;
|
|
break;
|
|
}
|
|
}
|
|
if (!ret && error != NULL) {
|
|
[*error retain];
|
|
}
|
|
[pool drain];
|
|
if (!ret && error != NULL) {
|
|
[*error autorelease];
|
|
}
|
|
return ret;
|
|
}
|
|
- (BOOL)verifyS3BucketName:(NSString *)s3BucketName computerUUID:(NSString *)computerUUID bucketUUID:(NSString *)bucketUUID error:(NSError **)error {
|
|
if (objectSHA1s == nil) {
|
|
if (![self loadObjectSHA1sForS3BucketName:s3BucketName computerUUID:computerUUID error:error]) {
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
NSError *saltError = nil;
|
|
ArqSalt *arqSalt = [[[ArqSalt alloc] initWithAccessKeyID:accessKey secretAccessKey:secretKey s3BucketName:s3BucketName computerUUID:computerUUID] autorelease];
|
|
NSData *salt = [arqSalt salt:&saltError];
|
|
if (salt == nil) {
|
|
if ([saltError code] != ERROR_NOT_FOUND) {
|
|
if (error != NULL) {
|
|
*error = saltError;
|
|
}
|
|
return NO;
|
|
}
|
|
}
|
|
ArqRepo *repo = [[[ArqRepo alloc] initWithS3Service:s3
|
|
s3BucketName:s3BucketName
|
|
computerUUID:computerUUID
|
|
bucketUUID:bucketUUID
|
|
encryptionPassword:encryptionPassword
|
|
salt:salt
|
|
error:error] autorelease];
|
|
if (repo == nil) {
|
|
return NO;
|
|
}
|
|
printf("\nverifying bucketUUID %s computerUUID %s s3Bucket %s\n", [bucketUUID UTF8String], [computerUUID UTF8String], [s3BucketName UTF8String]);
|
|
|
|
BucketVerifier *bucketVerifier = [[[BucketVerifier alloc] initWithS3Service:s3
|
|
s3BucketName:s3BucketName
|
|
computerUUID:computerUUID
|
|
bucketUUID:bucketUUID
|
|
s3ObjectSHA1s:objectSHA1s
|
|
verbose:verbose
|
|
repo:repo] autorelease];
|
|
if (![bucketVerifier verify:error]) {
|
|
return NO;
|
|
}
|
|
return YES;
|
|
}
|
|
@end
|
|
|
|
@implementation ArqVerifyCommand (internal)
|
|
- (BOOL)loadObjectSHA1sForS3BucketName:(NSString *)s3BucketName computerUUID:(NSString *)computerUUID error:(NSError **)error {
|
|
NSMutableSet *theObjectSHA1s = [NSMutableSet set];
|
|
NSString *objectsPrefix = [NSString stringWithFormat:@"/%@/%@/objects", s3BucketName, computerUUID];
|
|
printf("loading S3 object SHA1s with prefix %s\n", [objectsPrefix UTF8String]);
|
|
NSArray *objectPaths = [s3 pathsWithPrefix:objectsPrefix error:error];
|
|
if (objectPaths == nil) {
|
|
return NO;
|
|
}
|
|
for (NSString *objectPath in objectPaths) {
|
|
[theObjectSHA1s addObject:[objectPath lastPathComponent]];
|
|
}
|
|
objectSHA1s = [theObjectSHA1s retain];
|
|
printf("loaded %u object SHA1s with prefix %s\n", [objectSHA1s count], [objectsPrefix UTF8String]);
|
|
return YES;
|
|
}
|
|
@end
|