Added an option to explicitly give a SHA1 for the commit you want to restore.

This commit is contained in:
Stefan Reitshamer 2011-11-21 08:35:36 -05:00
parent 23ba1cc792
commit 395a17a05d
6 changed files with 58 additions and 26 deletions

View file

@ -39,6 +39,7 @@
NSString *encryptionPassword; NSString *encryptionPassword;
S3Service *s3; S3Service *s3;
NSString *path; NSString *path;
NSString *commitSHA1;
} }
- (BOOL)readArgc:(int)argc argv:(const char **)argv; - (BOOL)readArgc:(int)argc argv:(const char **)argv;
- (BOOL)execute:(NSError **)error; - (BOOL)execute:(NSError **)error;

View file

@ -80,6 +80,7 @@
[encryptionPassword release]; [encryptionPassword release];
[s3 release]; [s3 release];
[path release]; [path release];
[commitSHA1 release];
[super dealloc]; [super dealloc];
} }
- (BOOL)readArgc:(int)argc argv:(const char **)argv { - (BOOL)readArgc:(int)argc argv:(const char **)argv {
@ -98,6 +99,8 @@
setHSLogLevel(hsLogLevelForName(level)); setHSLogLevel(hsLogLevelForName(level));
} else if (path == nil) { } else if (path == nil) {
path = [[NSString alloc] initWithUTF8String:argv[i]]; path = [[NSString alloc] initWithUTF8String:argv[i]];
} else if (commitSHA1 == nil) {
commitSHA1 = [[NSString alloc] initWithUTF8String:argv[i]];
} else { } else {
fprintf(stderr, "warning: ignoring argument '%s'\n", argv[i]); fprintf(stderr, "warning: ignoring argument '%s'\n", argv[i]);
} }
@ -110,7 +113,7 @@
ret = [self printArqFolders:error]; ret = [self printArqFolders:error];
} else { } else {
ret = [self restorePath:error]; ret = [self restorePath:error];
} }
return ret; return ret;
} }
@end @end
@ -219,7 +222,7 @@
return NO; return NO;
} }
Restorer *restorer = [[[Restorer alloc] initWithRepo:repo bucketName:bucketName] autorelease]; Restorer *restorer = [[[Restorer alloc] initWithRepo:repo bucketName:bucketName commitSHA1:commitSHA1] autorelease];
if (![restorer restore:error]) { if (![restorer restore:error]) {
return NO; return NO;
} }

View file

@ -40,6 +40,7 @@
@interface Restorer : NSObject { @interface Restorer : NSObject {
ArqRepo *repo; ArqRepo *repo;
NSString *bucketName; NSString *bucketName;
NSString *commitSHA1;
NSString *rootPath; NSString *rootPath;
NSUInteger superUserNodeCount; NSUInteger superUserNodeCount;
NSMutableArray *restoreNodes; NSMutableArray *restoreNodes;
@ -51,10 +52,8 @@
unsigned long long transferred; unsigned long long transferred;
unsigned long long total; unsigned long long total;
BlobKey *headBlobKey; Tree *rootTree;
Commit *head;
Tree *headTree;
} }
- (id)initWithRepo:(ArqRepo *)theRepo bucketName:(NSString *)theBucketName; - (id)initWithRepo:(ArqRepo *)theRepo bucketName:(NSString *)theBucketName commitSHA1:(NSString *)theCommitSHA1;
- (BOOL)restore:(NSError **)error; - (BOOL)restore:(NSError **)error;
@end @end

View file

@ -50,6 +50,8 @@
#import "NSData-Gzip.h" #import "NSData-Gzip.h"
#import "GunzipInputStream.h" #import "GunzipInputStream.h"
#import "FileACL.h" #import "FileACL.h"
#import "BlobKey.h"
#define MAX_RETRIES (10) #define MAX_RETRIES (10)
#define MY_BUF_SIZE (8192) #define MY_BUF_SIZE (8192)
@ -61,7 +63,6 @@
- (BOOL)restoreNode:(Node *)theNode ofTree:(Tree *)theTree toPath:(NSString *)thePath error:(NSError **)error; - (BOOL)restoreNode:(Node *)theNode ofTree:(Tree *)theTree toPath:(NSString *)thePath error:(NSError **)error;
- (BOOL)needSuperUserForTree:(Tree *)theTree; - (BOOL)needSuperUserForTree:(Tree *)theTree;
- (BOOL)needSuperUserForTree:(Tree *)theTree node:(Node *)theNode; - (BOOL)needSuperUserForTree:(Tree *)theTree node:(Node *)theNode;
- (BOOL)performSuperUserOps:(NSError **)error;
- (BOOL)chownNode:(Node *)theNode ofTree:(Tree *)theTree atPath:(NSString *)thePath error:(NSError **)error; - (BOOL)chownNode:(Node *)theNode ofTree:(Tree *)theTree atPath:(NSString *)thePath error:(NSError **)error;
- (BOOL)chownTree:(Tree *)theTree atPath:(NSString *)thePath error:(NSError **)error; - (BOOL)chownTree:(Tree *)theTree atPath:(NSString *)thePath error:(NSError **)error;
- (BOOL)applyUID:(int)theUID gid:(int)theGID mode:(int)theMode rdev:(int)theRdev toPath:(NSString *)thePath error:(NSError **)error; - (BOOL)applyUID:(int)theUID gid:(int)theGID mode:(int)theMode rdev:(int)theRdev toPath:(NSString *)thePath error:(NSError **)error;
@ -77,10 +78,11 @@
@end @end
@implementation Restorer @implementation Restorer
- (id)initWithRepo:(ArqRepo *)theArqRepo bucketName:(NSString *)theBucketName { - (id)initWithRepo:(ArqRepo *)theArqRepo bucketName:(NSString *)theBucketName commitSHA1:(NSString *)theCommitSHA1 {
if (self = [super init]) { if (self = [super init]) {
repo = [theArqRepo retain]; repo = [theArqRepo retain];
bucketName = [theBucketName copy]; bucketName = [theBucketName copy];
commitSHA1 = [theCommitSHA1 copy];
rootPath = [[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:theBucketName] copy]; rootPath = [[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:theBucketName] copy];
restoreNodes = [[NSMutableArray alloc] init]; restoreNodes = [[NSMutableArray alloc] init];
hardlinks = [[NSMutableDictionary alloc] init]; hardlinks = [[NSMutableDictionary alloc] init];
@ -93,13 +95,12 @@
- (void)dealloc { - (void)dealloc {
[repo release]; [repo release];
[bucketName release]; [bucketName release];
[commitSHA1 release];
[rootPath release]; [rootPath release];
[restoreNodes release]; [restoreNodes release];
[hardlinks release]; [hardlinks release];
[errorsByPath release]; [errorsByPath release];
[headBlobKey release]; [rootTree release];
[head release];
[headTree release];
[super dealloc]; [super dealloc];
} }
- (BOOL)restore:(NSError **)error { - (BOOL)restore:(NSError **)error {
@ -111,20 +112,44 @@
HSLogError(@"failed to create directory %@", rootPath); HSLogError(@"failed to create directory %@", rootPath);
return NO; return NO;
} }
headBlobKey = [[repo headBlobKey:error] retain]; BlobKey *commitBlobKey = nil;
if (headBlobKey == nil) { Commit *commit = nil;
SETNSERROR([Restorer errorDomain], -1, @"no backup found"); NSError *myError = nil;
if (commitSHA1 != nil) {
commitBlobKey = [[[BlobKey alloc] initWithSHA1:commitSHA1 stretchEncryptionKey:YES] autorelease];
commit = [repo commitForBlobKey:commitBlobKey error:&myError];
if (commit == nil) {
HSLogError(@"error attempting to read commit for %@", commitBlobKey);
// Try without stretched encryption key.
commitBlobKey = [[[BlobKey alloc] initWithSHA1:commitSHA1 stretchEncryptionKey:NO] autorelease];
commit = [repo commitForBlobKey:commitBlobKey error:&myError];
if (commit == nil) {
HSLogError(@"error attempting to read commit for %@", commitBlobKey);
if (error != NULL) {
*error = myError;
}
return NO;
}
}
} else {
commitBlobKey = [[repo headBlobKey:error] retain];
if (commitBlobKey == nil) {
SETNSERROR([Restorer errorDomain], -1, @"no backup found");
return NO;
}
commit = [repo commitForBlobKey:commitBlobKey error:error];
if (commit == nil) {
return NO;
}
}
printf("restoring %scommit %s\n", (commitSHA1 == nil ? "head " : ""), [[commitBlobKey description] UTF8String]);
rootTree = [[repo treeForBlobKey:[commit treeBlobKey] error:error] retain];
if (rootTree == nil) {
return NO; return NO;
} }
head = [[repo commitForBlobKey:headBlobKey error:error] retain]; if (![self restoreTree:rootTree toPath:rootPath error:error]) {
if (head == nil) {
return NO;
}
headTree = [[repo treeForBlobKey:[head treeBlobKey] error:error] retain];
if (headTree == nil) {
return NO;
}
if (![self restoreTree:headTree toPath:rootPath error:error]) {
return NO; return NO;
} }
return YES; return YES;
@ -296,9 +321,6 @@
} }
return NO; return NO;
} }
- (BOOL)performSuperUserOps:(NSError **)error {
return [self chownTree:headTree atPath:rootPath error:error];
}
- (BOOL)chownNode:(Node *)theNode ofTree:(Tree *)theTree atPath:(NSString *)thePath error:(NSError **)error { - (BOOL)chownNode:(Node *)theNode ofTree:(Tree *)theTree atPath:(NSString *)thePath error:(NSError **)error {
if ([[errorsByPath allKeys] containsObject:thePath]) { if ([[errorsByPath allKeys] containsObject:thePath]) {
HSLogDebug(@"error restoring %@; skipping chownNode", thePath); HSLogDebug(@"error restoring %@; skipping chownNode", thePath);

View file

@ -39,6 +39,7 @@ static void printUsage(const char *exeName) {
fprintf(stderr, "Usage:\n"); fprintf(stderr, "Usage:\n");
fprintf(stderr, "\t%s [-l log_level]\n", exeName); fprintf(stderr, "\t%s [-l log_level]\n", exeName);
fprintf(stderr, "\t%s [-l log_level] /s3bucket/computerUUID/folderUUID\n", exeName); fprintf(stderr, "\t%s [-l log_level] /s3bucket/computerUUID/folderUUID\n", exeName);
fprintf(stderr, "\t%s [-l log_level] /s3bucket/computerUUID/folderUUID <commitSHA1>\n", exeName);
} }
int main (int argc, const char **argv) { int main (int argc, const char **argv) {
setHSLogLevel(HSLOG_LEVEL_WARN); setHSLogLevel(HSLOG_LEVEL_WARN);

View file

@ -51,6 +51,7 @@
F805B8C21160EC41007EC01E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8C11160EC41007EC01E /* Security.framework */; }; F805B8C21160EC41007EC01E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8C11160EC41007EC01E /* Security.framework */; };
F805B8CE1160ECD7007EC01E /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8CD1160ECD7007EC01E /* CoreServices.framework */; }; F805B8CE1160ECD7007EC01E /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8CD1160ECD7007EC01E /* CoreServices.framework */; };
F81426D714541A6C00D7E50A /* BackupSet.m in Sources */ = {isa = PBXBuildFile; fileRef = F81426D614541A6C00D7E50A /* BackupSet.m */; }; F81426D714541A6C00D7E50A /* BackupSet.m in Sources */ = {isa = PBXBuildFile; fileRef = F81426D614541A6C00D7E50A /* BackupSet.m */; };
F8373E0F14794D01005AFBE6 /* ReflogEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = F8373E0E14794D01005AFBE6 /* ReflogEntry.m */; };
F83C1A7411CA7C170001958F /* ArqRestoreCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B54C1160D3E6007EC01E /* ArqRestoreCommand.m */; }; F83C1A7411CA7C170001958F /* ArqRestoreCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B54C1160D3E6007EC01E /* ArqRestoreCommand.m */; };
F83C1A7711CA7C170001958F /* ArrayNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7421160DCFE007EC01E /* ArrayNode.m */; }; F83C1A7711CA7C170001958F /* ArrayNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7421160DCFE007EC01E /* ArrayNode.m */; };
F83C1A7811CA7C170001958F /* BooleanNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7441160DCFE007EC01E /* BooleanNode.m */; }; F83C1A7811CA7C170001958F /* BooleanNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7441160DCFE007EC01E /* BooleanNode.m */; };
@ -339,6 +340,8 @@
F805B8CD1160ECD7007EC01E /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; F805B8CD1160ECD7007EC01E /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
F81426D514541A6C00D7E50A /* BackupSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackupSet.h; sourceTree = "<group>"; }; F81426D514541A6C00D7E50A /* BackupSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackupSet.h; sourceTree = "<group>"; };
F81426D614541A6C00D7E50A /* BackupSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BackupSet.m; sourceTree = "<group>"; }; F81426D614541A6C00D7E50A /* BackupSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BackupSet.m; sourceTree = "<group>"; };
F8373E0D14794D01005AFBE6 /* ReflogEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReflogEntry.h; sourceTree = "<group>"; };
F8373E0E14794D01005AFBE6 /* ReflogEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReflogEntry.m; sourceTree = "<group>"; };
F83C1A5F11CA7A6B0001958F /* arq_verify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = arq_verify.m; sourceTree = "<group>"; }; F83C1A5F11CA7A6B0001958F /* arq_verify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = arq_verify.m; sourceTree = "<group>"; };
F83C1A6111CA7BD20001958F /* ArqVerifyCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArqVerifyCommand.h; sourceTree = "<group>"; }; F83C1A6111CA7BD20001958F /* ArqVerifyCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArqVerifyCommand.h; sourceTree = "<group>"; };
F83C1A6211CA7BD20001958F /* ArqVerifyCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArqVerifyCommand.m; sourceTree = "<group>"; }; F83C1A6211CA7BD20001958F /* ArqVerifyCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArqVerifyCommand.m; sourceTree = "<group>"; };
@ -549,6 +552,8 @@
F89A1F3D13FAC6820071D321 /* UserLibrary_Arq.m */, F89A1F3D13FAC6820071D321 /* UserLibrary_Arq.m */,
F81426D514541A6C00D7E50A /* BackupSet.h */, F81426D514541A6C00D7E50A /* BackupSet.h */,
F81426D614541A6C00D7E50A /* BackupSet.m */, F81426D614541A6C00D7E50A /* BackupSet.m */,
F8373E0D14794D01005AFBE6 /* ReflogEntry.h */,
F8373E0E14794D01005AFBE6 /* ReflogEntry.m */,
); );
name = Source; name = Source;
sourceTree = "<group>"; sourceTree = "<group>";
@ -980,6 +985,7 @@
F89A205413FAE2DA0071D321 /* LocalS3Signer.m in Sources */, F89A205413FAE2DA0071D321 /* LocalS3Signer.m in Sources */,
F89A205A13FAE3010071D321 /* DataOutputStream.m in Sources */, F89A205A13FAE3010071D321 /* DataOutputStream.m in Sources */,
F81426D714541A6C00D7E50A /* BackupSet.m in Sources */, F81426D714541A6C00D7E50A /* BackupSet.m in Sources */,
F8373E0F14794D01005AFBE6 /* ReflogEntry.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };