mirror of
https://github.com/samsonjs/arq_restore.git
synced 2026-03-25 09:25:53 +00:00
Added an option to explicitly give a SHA1 for the commit you want to restore.
This commit is contained in:
parent
23ba1cc792
commit
395a17a05d
6 changed files with 58 additions and 26 deletions
|
|
@ -39,6 +39,7 @@
|
|||
NSString *encryptionPassword;
|
||||
S3Service *s3;
|
||||
NSString *path;
|
||||
NSString *commitSHA1;
|
||||
}
|
||||
- (BOOL)readArgc:(int)argc argv:(const char **)argv;
|
||||
- (BOOL)execute:(NSError **)error;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
[encryptionPassword release];
|
||||
[s3 release];
|
||||
[path release];
|
||||
[commitSHA1 release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)readArgc:(int)argc argv:(const char **)argv {
|
||||
|
|
@ -98,6 +99,8 @@
|
|||
setHSLogLevel(hsLogLevelForName(level));
|
||||
} else if (path == nil) {
|
||||
path = [[NSString alloc] initWithUTF8String:argv[i]];
|
||||
} else if (commitSHA1 == nil) {
|
||||
commitSHA1 = [[NSString alloc] initWithUTF8String:argv[i]];
|
||||
} else {
|
||||
fprintf(stderr, "warning: ignoring argument '%s'\n", argv[i]);
|
||||
}
|
||||
|
|
@ -110,7 +113,7 @@
|
|||
ret = [self printArqFolders:error];
|
||||
} else {
|
||||
ret = [self restorePath:error];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
|
|
@ -219,7 +222,7 @@
|
|||
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]) {
|
||||
return NO;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
@interface Restorer : NSObject {
|
||||
ArqRepo *repo;
|
||||
NSString *bucketName;
|
||||
NSString *commitSHA1;
|
||||
NSString *rootPath;
|
||||
NSUInteger superUserNodeCount;
|
||||
NSMutableArray *restoreNodes;
|
||||
|
|
@ -51,10 +52,8 @@
|
|||
unsigned long long transferred;
|
||||
unsigned long long total;
|
||||
|
||||
BlobKey *headBlobKey;
|
||||
Commit *head;
|
||||
Tree *headTree;
|
||||
Tree *rootTree;
|
||||
}
|
||||
- (id)initWithRepo:(ArqRepo *)theRepo bucketName:(NSString *)theBucketName;
|
||||
- (id)initWithRepo:(ArqRepo *)theRepo bucketName:(NSString *)theBucketName commitSHA1:(NSString *)theCommitSHA1;
|
||||
- (BOOL)restore:(NSError **)error;
|
||||
@end
|
||||
|
|
|
|||
62
Restorer.m
62
Restorer.m
|
|
@ -50,6 +50,8 @@
|
|||
#import "NSData-Gzip.h"
|
||||
#import "GunzipInputStream.h"
|
||||
#import "FileACL.h"
|
||||
#import "BlobKey.h"
|
||||
|
||||
|
||||
#define MAX_RETRIES (10)
|
||||
#define MY_BUF_SIZE (8192)
|
||||
|
|
@ -61,7 +63,6 @@
|
|||
- (BOOL)restoreNode:(Node *)theNode ofTree:(Tree *)theTree toPath:(NSString *)thePath error:(NSError **)error;
|
||||
- (BOOL)needSuperUserForTree:(Tree *)theTree;
|
||||
- (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)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;
|
||||
|
|
@ -77,10 +78,11 @@
|
|||
@end
|
||||
|
||||
@implementation Restorer
|
||||
- (id)initWithRepo:(ArqRepo *)theArqRepo bucketName:(NSString *)theBucketName {
|
||||
- (id)initWithRepo:(ArqRepo *)theArqRepo bucketName:(NSString *)theBucketName commitSHA1:(NSString *)theCommitSHA1 {
|
||||
if (self = [super init]) {
|
||||
repo = [theArqRepo retain];
|
||||
bucketName = [theBucketName copy];
|
||||
commitSHA1 = [theCommitSHA1 copy];
|
||||
rootPath = [[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:theBucketName] copy];
|
||||
restoreNodes = [[NSMutableArray alloc] init];
|
||||
hardlinks = [[NSMutableDictionary alloc] init];
|
||||
|
|
@ -93,13 +95,12 @@
|
|||
- (void)dealloc {
|
||||
[repo release];
|
||||
[bucketName release];
|
||||
[commitSHA1 release];
|
||||
[rootPath release];
|
||||
[restoreNodes release];
|
||||
[hardlinks release];
|
||||
[errorsByPath release];
|
||||
[headBlobKey release];
|
||||
[head release];
|
||||
[headTree release];
|
||||
[rootTree release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)restore:(NSError **)error {
|
||||
|
|
@ -111,20 +112,44 @@
|
|||
HSLogError(@"failed to create directory %@", rootPath);
|
||||
return NO;
|
||||
}
|
||||
headBlobKey = [[repo headBlobKey:error] retain];
|
||||
if (headBlobKey == nil) {
|
||||
SETNSERROR([Restorer errorDomain], -1, @"no backup found");
|
||||
BlobKey *commitBlobKey = nil;
|
||||
Commit *commit = nil;
|
||||
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;
|
||||
}
|
||||
head = [[repo commitForBlobKey:headBlobKey error:error] retain];
|
||||
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]) {
|
||||
if (![self restoreTree:rootTree toPath:rootPath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
|
|
@ -296,9 +321,6 @@
|
|||
}
|
||||
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 {
|
||||
if ([[errorsByPath allKeys] containsObject:thePath]) {
|
||||
HSLogDebug(@"error restoring %@; skipping chownNode", thePath);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ static void printUsage(const char *exeName) {
|
|||
fprintf(stderr, "Usage:\n");
|
||||
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 <commitSHA1>\n", exeName);
|
||||
}
|
||||
int main (int argc, const char **argv) {
|
||||
setHSLogLevel(HSLOG_LEVEL_WARN);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
F805B8C21160EC41007EC01E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8C11160EC41007EC01E /* Security.framework */; };
|
||||
F805B8CE1160ECD7007EC01E /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8CD1160ECD7007EC01E /* CoreServices.framework */; };
|
||||
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 */; };
|
||||
F83C1A7711CA7C170001958F /* ArrayNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7421160DCFE007EC01E /* ArrayNode.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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
|
@ -549,6 +552,8 @@
|
|||
F89A1F3D13FAC6820071D321 /* UserLibrary_Arq.m */,
|
||||
F81426D514541A6C00D7E50A /* BackupSet.h */,
|
||||
F81426D614541A6C00D7E50A /* BackupSet.m */,
|
||||
F8373E0D14794D01005AFBE6 /* ReflogEntry.h */,
|
||||
F8373E0E14794D01005AFBE6 /* ReflogEntry.m */,
|
||||
);
|
||||
name = Source;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -980,6 +985,7 @@
|
|||
F89A205413FAE2DA0071D321 /* LocalS3Signer.m in Sources */,
|
||||
F89A205A13FAE3010071D321 /* DataOutputStream.m in Sources */,
|
||||
F81426D714541A6C00D7E50A /* BackupSet.m in Sources */,
|
||||
F8373E0F14794D01005AFBE6 /* ReflogEntry.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue