mirror of
https://github.com/samsonjs/arq_restore.git
synced 2026-04-27 15:07:44 +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;
|
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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
62
Restorer.m
62
Restorer.m
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue