mirror of
https://github.com/samsonjs/arq_restore.git
synced 2026-03-25 09:25:53 +00:00
initial commit
This commit is contained in:
commit
4a346a274c
187 changed files with 16525 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
build
|
||||
43
ArqFolder.h
Normal file
43
ArqFolder.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "DictNode.h"
|
||||
|
||||
@interface ArqFolder : NSObject {
|
||||
NSString *s3Path;
|
||||
NSString *localPath;
|
||||
}
|
||||
- (id)initWithS3Path:(NSString *)theS3Path plist:(DictNode *)plist;
|
||||
- (NSString *)s3Path;
|
||||
- (NSString *)localPath;
|
||||
@end
|
||||
55
ArqFolder.m
Normal file
55
ArqFolder.m
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "ArqFolder.h"
|
||||
#import "DictNode.h"
|
||||
|
||||
@implementation ArqFolder
|
||||
- (id)initWithS3Path:(NSString *)theS3Path plist:(DictNode *)plist {
|
||||
if (self = [super init]) {
|
||||
s3Path = [theS3Path copy];
|
||||
localPath = [[[plist stringNodeForKey:@"LocalPath"] stringValue] copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[s3Path release];
|
||||
[localPath release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSString *)s3Path {
|
||||
return s3Path;
|
||||
}
|
||||
- (NSString *)localPath {
|
||||
return localPath;
|
||||
}
|
||||
@end
|
||||
44
ArqRestoreCommand.h
Normal file
44
ArqRestoreCommand.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class S3Service;
|
||||
|
||||
@interface ArqRestoreCommand : NSObject {
|
||||
NSString *accessKey;
|
||||
NSString *secretKey;
|
||||
NSString *encryptionPassword;
|
||||
S3Service *s3;
|
||||
}
|
||||
- (BOOL)printArqFolders:(NSError **)error;
|
||||
- (BOOL)restorePath:(NSString *)path error:(NSError **)error;
|
||||
@end
|
||||
191
ArqRestoreCommand.m
Normal file
191
ArqRestoreCommand.m
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "ArqRestoreCommand.h"
|
||||
#import "SetNSError.h"
|
||||
#import "S3AuthorizationProvider.h"
|
||||
#import "S3Service.h"
|
||||
#import "RegexKitLite.h"
|
||||
#import "DictNode.h"
|
||||
#import "ArqFolder.h"
|
||||
#import "HTTP.h"
|
||||
#import "Restorer.h"
|
||||
|
||||
@interface ArqRestoreCommand (internal)
|
||||
- (BOOL)validateS3Keys:(NSError **)error;
|
||||
- (NSArray *)s3BucketNames:(NSError **)error;
|
||||
- (NSString *)s3BucketNameForRegion:(int)s3BucketRegion;
|
||||
@end
|
||||
|
||||
@implementation ArqRestoreCommand
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
char *theAccessKey = getenv("ARQ_ACCESS_KEY");
|
||||
if (theAccessKey != NULL) {
|
||||
accessKey = [[NSString alloc] initWithUTF8String:theAccessKey];
|
||||
}
|
||||
char *theSecretKey = getenv("ARQ_SECRET_KEY");
|
||||
if (theSecretKey != NULL) {
|
||||
secretKey = [[NSString alloc] initWithUTF8String:theSecretKey];
|
||||
}
|
||||
char *theEncryptionPassword = getenv("ARQ_ENCRYPTION_PASSWORD");
|
||||
if (theEncryptionPassword != NULL) {
|
||||
encryptionPassword = [[NSString alloc] initWithUTF8String:theEncryptionPassword];
|
||||
}
|
||||
if (accessKey != nil && secretKey != nil) {
|
||||
S3AuthorizationProvider *sap = [[S3AuthorizationProvider alloc] initWithAccessKey:accessKey secretKey:secretKey];
|
||||
s3 = [[S3Service alloc] initWithS3AuthorizationProvider:sap useSSL:NO retryOnNetworkError:YES];
|
||||
[sap release];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[accessKey release];
|
||||
[secretKey release];
|
||||
[encryptionPassword release];
|
||||
[s3 release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)printArqFolders:(NSError **)error {
|
||||
if (![self validateS3Keys:error]) {
|
||||
return NO;
|
||||
}
|
||||
NSArray *s3BucketNames = [self s3BucketNames:error];
|
||||
if (s3BucketNames == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSMutableArray *computerUUIDPaths = [NSMutableArray array];
|
||||
for (NSString *s3BucketName in s3BucketNames) {
|
||||
NSString *computerUUIDPrefix = [NSString stringWithFormat:@"/%@/", s3BucketName];
|
||||
NSError *myError = nil;
|
||||
NSArray *computerUUIDs = [s3 commonPrefixesForPathPrefix:computerUUIDPrefix delimiter:@"/" error:&myError];
|
||||
if (computerUUIDs == nil) {
|
||||
if ([[myError domain] isEqualToString:[S3Service serverErrorDomain]] && [myError code] == HTTP_NOT_FOUND) {
|
||||
// Skip.
|
||||
} else {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
for (NSString *computerUUID in computerUUIDs) {
|
||||
[computerUUIDPaths addObject:[computerUUIDPrefix stringByAppendingPathComponent:computerUUID]];
|
||||
}
|
||||
}
|
||||
for (NSString *computerUUIDPath in computerUUIDPaths) {
|
||||
NSString *computerBucketsPrefix = [computerUUIDPath stringByAppendingPathComponent:@"buckets"];
|
||||
NSArray *s3BucketUUIDPaths = [s3 pathsWithPrefix:computerBucketsPrefix error:error];
|
||||
if (s3BucketUUIDPaths == nil) {
|
||||
return NO;
|
||||
}
|
||||
for (NSString *uuidPath in s3BucketUUIDPaths) {
|
||||
NSData *data = [s3 dataAtPath:uuidPath error:error];
|
||||
if (data == nil) {
|
||||
return NO;
|
||||
}
|
||||
DictNode *plist = [DictNode dictNodeWithXMLData:data error:error];
|
||||
if (plist == nil) {
|
||||
return NO;
|
||||
}
|
||||
printf("s3 path=%s\tlocal path=%s\n", [uuidPath UTF8String], [[[plist stringNodeForKey:@"LocalPath"] stringValue] UTF8String]);
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)restorePath:(NSString *)path error:(NSError **)error {
|
||||
if (![self validateS3Keys:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (encryptionPassword == nil) {
|
||||
SETNSERROR(@"ArqErrorDomain", -1, @"missing ARQ_ENCRYPTION_PASSWORD environment variable");
|
||||
return NO;
|
||||
}
|
||||
NSString *pattern = @"^/([^/]+)/([^/]+)/buckets/([^/]+)";
|
||||
NSRange s3BucketNameRange = [path rangeOfRegex:pattern capture:1];
|
||||
NSRange computerUUIDRange = [path rangeOfRegex:pattern capture:2];
|
||||
NSRange bucketUUIDRange = [path rangeOfRegex:pattern capture:3];
|
||||
if (s3BucketNameRange.location == NSNotFound || computerUUIDRange.location == NSNotFound || bucketUUIDRange.location == NSNotFound) {
|
||||
SETNSERROR(@"ArqErrorDomain", -1, @"invalid S3 path");
|
||||
return NO;
|
||||
}
|
||||
NSData *data = [s3 dataAtPath:path error:error];
|
||||
if (data == nil) {
|
||||
return NO;
|
||||
}
|
||||
DictNode *plist = [DictNode dictNodeWithXMLData:data error:error];
|
||||
if (plist == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSString *s3BucketName = [path substringWithRange:s3BucketNameRange];
|
||||
NSString *computerUUID = [path substringWithRange:computerUUIDRange];
|
||||
NSString *bucketUUID = [path substringWithRange:bucketUUIDRange];
|
||||
NSString *bucketName = [[plist stringNodeForKey:@"BucketName"] stringValue];
|
||||
Restorer *restorer = [[[Restorer alloc] initWithS3Service:s3 s3BucketName:s3BucketName computerUUID:computerUUID bucketUUID:bucketUUID bucketName:bucketName encryptionKey:encryptionPassword] autorelease];
|
||||
if (![restorer restore:error]) {
|
||||
return NO;
|
||||
}
|
||||
printf("restored files are in %s\n", [bucketName fileSystemRepresentation]);
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ArqRestoreCommand (internal)
|
||||
- (BOOL)validateS3Keys:(NSError **)error {
|
||||
if (accessKey == nil) {
|
||||
SETNSERROR(@"ArqErrorDomain", -1, @"missing ARQ_ACCESS_KEY environment variable");
|
||||
return NO;
|
||||
}
|
||||
if (secretKey == nil) {
|
||||
SETNSERROR(@"ArqErrorDomain", -1, @"missing ARQ_SECRET_KEY environment variable");
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (NSArray *)s3BucketNames:(NSError **)error {
|
||||
return [NSArray arrayWithObjects:
|
||||
[self s3BucketNameForRegion:BUCKET_REGION_US_STANDARD],
|
||||
[self s3BucketNameForRegion:BUCKET_REGION_US_WEST],
|
||||
[self s3BucketNameForRegion:BUCKET_REGION_EU],
|
||||
nil];
|
||||
}
|
||||
- (NSString *)s3BucketNameForRegion:(int)s3BucketRegion {
|
||||
NSString *regionSuffix = @"";
|
||||
if (s3BucketRegion == BUCKET_REGION_US_WEST) {
|
||||
regionSuffix = @".us-west-1";
|
||||
} else if (s3BucketRegion == BUCKET_REGION_EU) {
|
||||
regionSuffix = @".eu";
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@.com.haystacksoftware.arq%@", [accessKey lowercaseString], regionSuffix];
|
||||
}
|
||||
@end
|
||||
40
ArqUserLibrary.h
Normal file
40
ArqUserLibrary.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
@interface ArqUserLibrary : NSObject {
|
||||
|
||||
}
|
||||
+ (NSString *)arqCachesPath;
|
||||
@end
|
||||
40
ArqUserLibrary.m
Normal file
40
ArqUserLibrary.m
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "ArqUserLibrary.h"
|
||||
|
||||
|
||||
@implementation ArqUserLibrary
|
||||
+ (NSString *)arqCachesPath {
|
||||
return [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Arq/Caches.noindex"];
|
||||
}
|
||||
@end
|
||||
62
Commit.h
Normal file
62
Commit.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Blob.h"
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
#define CURRENT_COMMIT_VERSION 3
|
||||
|
||||
@interface Commit : NSObject {
|
||||
int commitVersion;
|
||||
NSString *_author;
|
||||
NSString *_comment;
|
||||
NSMutableSet *_parentCommitSHA1s;
|
||||
NSString *_treeSHA1;
|
||||
NSString *_location;
|
||||
NSString *_computer;
|
||||
NSString *_mergeCommonAncestorCommitSHA1;
|
||||
NSDate *_creationDate;
|
||||
NSArray *_commitFailedFiles;
|
||||
}
|
||||
- (id)initWithBufferedInputStream:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
|
||||
@property(readonly,copy) NSString *author;
|
||||
@property(readonly,copy) NSString *comment;
|
||||
@property(readonly,copy) NSString *treeSHA1;
|
||||
@property(readonly,retain) NSSet *parentCommitSHA1s;
|
||||
@property(readonly,copy) NSString *location;
|
||||
@property(readonly,copy) NSString *computer;
|
||||
@property(readonly,copy) NSString *mergeCommonAncestorCommitSHA1;
|
||||
@property(readonly,retain) NSDate *creationDate;
|
||||
@property(readonly,retain) NSArray *commitFailedFiles;
|
||||
@end
|
||||
183
Commit.m
Normal file
183
Commit.m
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "IntegerIO.h"
|
||||
#import "DateIO.h"
|
||||
#import "StringIO.h"
|
||||
#import "Commit.h"
|
||||
#import "Blob.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "RegexKitLite.h"
|
||||
#import "SetNSError.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "CommitFailedFile.h"
|
||||
|
||||
#define HEADER_LENGTH (10)
|
||||
|
||||
@interface Commit (internal)
|
||||
- (BOOL)readHeader:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation Commit
|
||||
@synthesize author = _author,
|
||||
comment = _comment,
|
||||
treeSHA1 = _treeSHA1,
|
||||
parentCommitSHA1s = _parentCommitSHA1s,
|
||||
location = _location,
|
||||
computer = _computer,
|
||||
mergeCommonAncestorCommitSHA1 = _mergeCommonAncestorCommitSHA1,
|
||||
creationDate = _creationDate,
|
||||
commitFailedFiles = _commitFailedFiles;
|
||||
|
||||
- (id)initWithBufferedInputStream:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
_parentCommitSHA1s = [[NSMutableSet alloc] init];
|
||||
if (![self readHeader:is error:error]) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
BOOL ret = NO;
|
||||
do {
|
||||
if (![StringIO read:&_author from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[_author retain];
|
||||
|
||||
if (![StringIO read:&_comment from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[_comment retain];
|
||||
|
||||
uint64_t parentCommitKeyCount = 0;
|
||||
if (![IntegerIO readUInt64:&parentCommitKeyCount from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
for (uint64_t i = 0; i < parentCommitKeyCount; i++) {
|
||||
NSString *key;
|
||||
if (![StringIO read:&key from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[_parentCommitSHA1s addObject:key];
|
||||
}
|
||||
|
||||
if (![StringIO read:&_treeSHA1 from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[_treeSHA1 retain];
|
||||
|
||||
if (![StringIO read:&_location from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[_location retain];
|
||||
|
||||
NSRange computerRange = [_location rangeOfRegex:@"^file://([^/]+)/" capture:1];
|
||||
if (computerRange.location != NSNotFound) {
|
||||
_computer = [[_location substringWithRange:computerRange] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
} else {
|
||||
_computer = @"";
|
||||
}
|
||||
[_computer retain];
|
||||
|
||||
if (![StringIO read:&_mergeCommonAncestorCommitSHA1 from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[_mergeCommonAncestorCommitSHA1 retain];
|
||||
|
||||
if (![DateIO read:&_creationDate from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[_creationDate retain];
|
||||
if (commitVersion >= 3) {
|
||||
uint64_t commitFailedFileCount = 0;
|
||||
if (![IntegerIO readUInt64:&commitFailedFileCount from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
NSMutableArray *commitFailedFiles = [NSMutableArray array];
|
||||
for (uint64_t index = 0; index < commitFailedFileCount; index++) {
|
||||
CommitFailedFile *cff = [[CommitFailedFile alloc] initWithInputStream:is error:error];
|
||||
if (cff == nil) {
|
||||
break;
|
||||
}
|
||||
[commitFailedFiles addObject:cff];
|
||||
[cff release];
|
||||
}
|
||||
_commitFailedFiles = [commitFailedFiles retain];
|
||||
}
|
||||
ret = YES;
|
||||
} while (0);
|
||||
if (!ret) {
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)release {
|
||||
[super release];
|
||||
}
|
||||
- (void)dealloc {
|
||||
[_author release];
|
||||
[_comment release];
|
||||
[_parentCommitSHA1s release];
|
||||
[_treeSHA1 release];
|
||||
[_location release];
|
||||
[_computer release];
|
||||
[_mergeCommonAncestorCommitSHA1 release];
|
||||
[_creationDate release];
|
||||
[_commitFailedFiles release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation Commit (internal)
|
||||
- (BOOL)readHeader:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
unsigned char *headerBytes = [is readExactly:HEADER_LENGTH error:error];
|
||||
if (headerBytes == NULL) {
|
||||
return NO;
|
||||
}
|
||||
NSString *header = [[[NSString alloc] initWithBytes:headerBytes length:HEADER_LENGTH encoding:NSASCIIStringEncoding] autorelease];
|
||||
NSRange versionRange = [header rangeOfRegex:@"^CommitV(\\d{3})$" capture:1];
|
||||
commitVersion = 0;
|
||||
if (versionRange.location != NSNotFound) {
|
||||
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
|
||||
NSNumber *number = [nf numberFromString:[header substringWithRange:versionRange]];
|
||||
commitVersion = [number intValue];
|
||||
[nf release];
|
||||
}
|
||||
if (commitVersion > CURRENT_COMMIT_VERSION || commitVersion < 2) {
|
||||
SETNSERROR(@"TreeErrorDomain", ERROR_INVALID_OBJECT_VERSION, @"invalid Commit header");
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
|
||||
}
|
||||
@end
|
||||
44
CommitFailedFile.h
Normal file
44
CommitFailedFile.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@protocol BufferedInputStream;
|
||||
|
||||
@interface CommitFailedFile : NSObject {
|
||||
NSString *relativePath;
|
||||
NSString *errorMessage;
|
||||
}
|
||||
- (id)initWithInputStream:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
- (NSString *)relativePath;
|
||||
- (NSString *)errorMessage;
|
||||
- (void)writeTo:(NSMutableData *)data;
|
||||
@end
|
||||
65
CommitFailedFile.m
Normal file
65
CommitFailedFile.m
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "CommitFailedFile.h"
|
||||
#import "StringIO.h"
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@implementation CommitFailedFile
|
||||
- (id)initWithInputStream:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
if (![StringIO read:&relativePath from:is error:error]
|
||||
|| ![StringIO read:&errorMessage from:is error:error]) {
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
[relativePath retain];
|
||||
[errorMessage retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[relativePath release];
|
||||
[errorMessage release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSString *)relativePath {
|
||||
return [[relativePath retain] autorelease];
|
||||
}
|
||||
- (NSString *)errorMessage {
|
||||
return [[errorMessage retain] autorelease];
|
||||
}
|
||||
- (void)writeTo:(NSMutableData *)data {
|
||||
[StringIO write:relativePath to:data];
|
||||
[StringIO write:errorMessage to:data];
|
||||
}
|
||||
@end
|
||||
53
DiskPack.h
Normal file
53
DiskPack.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class S3Service;
|
||||
@class ServerBlob;
|
||||
|
||||
@interface DiskPack : NSObject {
|
||||
S3Service *s3;
|
||||
NSString *s3BucketName;
|
||||
NSString *computerUUID;
|
||||
NSString *packSetName;
|
||||
NSString *packSHA1;
|
||||
NSString *s3Path;
|
||||
NSString *localPath;
|
||||
}
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1;
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1;
|
||||
- (id)initWithS3Service:(S3Service *)theS3 s3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1;
|
||||
- (BOOL)makeLocal:(NSError **)error;
|
||||
- (ServerBlob *)newServerBlobForObjectAtOffset:(unsigned long long)offset error:(NSError **)error;
|
||||
- (BOOL)fileLength:(unsigned long long *)length error:(NSError **)error;
|
||||
- (NSArray *)sortedPackIndexEntries:(NSError **)error;
|
||||
@end
|
||||
232
DiskPack.m
Normal file
232
DiskPack.m
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#import "DiskPack.h"
|
||||
#import "SetNSError.h"
|
||||
#import "FDInputStream.h"
|
||||
#import "StringIO.h"
|
||||
#import "IntegerIO.h"
|
||||
#import "PackSetSet.h"
|
||||
#import "ServerBlob.h"
|
||||
#import "NSFileManager_extra.h"
|
||||
#import "S3Service.h"
|
||||
#import "ServerBlob.h"
|
||||
#import "FileInputStream.h"
|
||||
#import "FileOutputStream.h"
|
||||
#import "Streams.h"
|
||||
#import "PackSet.h"
|
||||
#import "S3ObjectReceiver.h"
|
||||
#import "S3ObjectMetadata.h"
|
||||
#import "PackIndexEntry.h"
|
||||
#import "SHA1Hash.h"
|
||||
|
||||
|
||||
@interface DiskPack (internal)
|
||||
- (BOOL)savePack:(ServerBlob *)sb bytesWritten:(unsigned long long *)written error:(NSError **)error;
|
||||
- (NSArray *)sortedPackIndexEntriesFromStream:(id <BufferedInputStream>)fis error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation DiskPack
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1 {
|
||||
return [NSString stringWithFormat:@"%@/%@.pack", [PackSet s3PathWithS3BucketName:theS3BucketName computerUUID:theComputerUUID packSetName:thePackSetName], thePackSHA1];
|
||||
}
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1 {
|
||||
return [NSString stringWithFormat:@"%@/%@/%@.pack", [PackSet localPathWithComputerUUID:theComputerUUID packSetName:thePackSetName], [thePackSHA1 substringToIndex:2], [thePackSHA1 substringFromIndex:2]];
|
||||
}
|
||||
- (id)initWithS3Service:(S3Service *)theS3 s3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1 {
|
||||
if (self = [super init]) {
|
||||
s3 = [theS3 retain];
|
||||
s3BucketName = [theS3BucketName retain];
|
||||
computerUUID = [theComputerUUID retain];
|
||||
packSetName = [thePackSetName retain];
|
||||
packSHA1 = [thePackSHA1 retain];
|
||||
s3Path = [[DiskPack s3PathWithS3BucketName:s3BucketName computerUUID:computerUUID packSetName:packSetName packSHA1:packSHA1] retain];
|
||||
localPath = [[DiskPack localPathWithComputerUUID:computerUUID packSetName:packSetName packSHA1:packSHA1] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[s3 release];
|
||||
[s3BucketName release];
|
||||
[computerUUID release];
|
||||
[packSetName release];
|
||||
[packSHA1 release];
|
||||
[s3Path release];
|
||||
[localPath release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)makeLocal:(NSError **)error {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
BOOL ret = NO;
|
||||
if (![fm fileExistsAtPath:localPath]) {
|
||||
HSLogDebug(@"packset %@: making pack %@ local", packSetName, packSHA1);
|
||||
ServerBlob *sb = [s3 newServerBlobAtPath:s3Path error:error];
|
||||
if (sb != nil) {
|
||||
unsigned long long bytesWritten;
|
||||
ret = [self savePack:sb bytesWritten:&bytesWritten error:error];
|
||||
[sb release];
|
||||
}
|
||||
} else {
|
||||
ret = YES;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (ServerBlob *)newServerBlobForObjectAtOffset:(unsigned long long)offset error:(NSError **)error {
|
||||
int fd = open([localPath fileSystemRepresentation], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s: %@", strerror(errno), localPath);
|
||||
return nil;
|
||||
}
|
||||
ServerBlob *ret = nil;
|
||||
FDInputStream *fdis = [[FDInputStream alloc] initWithFD:fd];
|
||||
do {
|
||||
if (lseek(fd, offset, SEEK_SET) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"lseek(%@, %qu): %s", localPath, offset, strerror(errno));
|
||||
break;
|
||||
}
|
||||
NSString *mimeType;
|
||||
NSString *downloadName;
|
||||
if (![StringIO read:&mimeType from:fdis error:error] || ![StringIO read:&downloadName from:fdis error:error]) {
|
||||
break;
|
||||
}
|
||||
uint64_t dataLen = 0;
|
||||
if (![IntegerIO readUInt64:&dataLen from:fdis error:error]) {
|
||||
break;
|
||||
}
|
||||
NSData *data = nil;
|
||||
if (dataLen > 0) {
|
||||
const unsigned char *bytes = [fdis readExactly:dataLen error:error];
|
||||
if (bytes == NULL) {
|
||||
break;
|
||||
}
|
||||
data = [NSData dataWithBytes:bytes length:dataLen];
|
||||
} else {
|
||||
data = [NSData data];
|
||||
}
|
||||
ret = [[ServerBlob alloc] initWithData:data mimeType:mimeType downloadName:downloadName];
|
||||
} while (0);
|
||||
close(fd);
|
||||
[fdis release];
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)fileLength:(unsigned long long *)length error:(NSError **)error {
|
||||
struct stat st;
|
||||
if (lstat([localPath fileSystemRepresentation], &st) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"lstat(%@): %s", localPath, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
*length = st.st_size;
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)copyToPath:(NSString *)dest error:(NSError **)error {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
if ([fm fileExistsAtPath:dest] && ![fm removeItemAtPath:dest error:error]) {
|
||||
HSLogError(@"error removing old mutable pack at %@", dest);
|
||||
return NO;
|
||||
}
|
||||
if (![fm ensureParentPathExistsForPath:dest error:error] || ![fm copyItemAtPath:localPath toPath:dest error:error]) {
|
||||
HSLogError(@"error copying pack %@ to %@", localPath, dest);
|
||||
return NO;
|
||||
}
|
||||
HSLogDebug(@"copied %@ to %@", localPath, dest);
|
||||
return YES;
|
||||
}
|
||||
- (NSArray *)sortedPackIndexEntries:(NSError **)error {
|
||||
unsigned long long length;
|
||||
if (![self fileLength:&length error:error]) {
|
||||
return NO;
|
||||
}
|
||||
FileInputStream *fis = [[FileInputStream alloc] initWithPath:localPath length:length];
|
||||
NSArray *ret = [self sortedPackIndexEntriesFromStream:fis error:error];
|
||||
[fis release];
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DiskPack (internal)
|
||||
- (BOOL)savePack:(ServerBlob *)sb bytesWritten:(unsigned long long *)written error:(NSError **)error {
|
||||
if (![[NSFileManager defaultManager] ensureParentPathExistsForPath:localPath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
id <InputStream> is = [sb newInputStream];
|
||||
NSError *myError;
|
||||
BOOL ret = [Streams transferFrom:is atomicallyToFile:localPath bytesWritten:written error:&myError];
|
||||
if (ret) {
|
||||
HSLogDebug(@"wrote %qu bytes to %@", *written, localPath);
|
||||
} else {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
HSLogError(@"error making pack %@ local at %@: %@", packSHA1, localPath, [myError localizedDescription]);
|
||||
}
|
||||
[is release];
|
||||
return ret;
|
||||
}
|
||||
- (NSArray *)sortedPackIndexEntriesFromStream:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
uint32_t packSig;
|
||||
uint32_t packVersion;
|
||||
if (![IntegerIO readUInt32:&packSig from:is error:error] || ![IntegerIO readUInt32:&packVersion from:is error:error]) {
|
||||
return nil;
|
||||
}
|
||||
if (packSig != 0x5041434b) { // "PACK"
|
||||
SETNSERROR(@"PackErrorDomain", -1, @"invalid pack signature");
|
||||
return nil;
|
||||
}
|
||||
if (packVersion != 2) {
|
||||
SETNSERROR(@"PackErrorDomain", -1, @"invalid pack version");
|
||||
}
|
||||
uint32_t objectCount;
|
||||
if (![IntegerIO readUInt32:&objectCount from:is error:error]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *ret = [NSMutableArray array];
|
||||
for (uint32_t index = 0; index < objectCount; index++) {
|
||||
uint64_t offset = [is bytesReceived];
|
||||
NSString *mimeType;
|
||||
NSString *name;
|
||||
uint64_t length;
|
||||
if (![StringIO read:&mimeType from:is error:error] || ![StringIO read:&name from:is error:error] || ![IntegerIO readUInt64:&length from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
NSString *objectSHA1 = [SHA1Hash hashStream:is withlength:length error:error];
|
||||
if (objectSHA1 == nil) {
|
||||
return NO;
|
||||
}
|
||||
PackIndexEntry *pie = [[PackIndexEntry alloc] initWithPackSHA1:packSHA1 offset:offset dataLength:length objectSHA1:objectSHA1];
|
||||
[ret addObject:pie];
|
||||
[pie release];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
52
DiskPackIndex.h
Normal file
52
DiskPackIndex.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class PackIndexEntry;
|
||||
@class S3Service;
|
||||
|
||||
@interface DiskPackIndex : NSObject {
|
||||
S3Service *s3;
|
||||
NSString *s3BucketName;
|
||||
NSString *computerUUID;
|
||||
NSString *packSetName;
|
||||
NSString *packSHA1;
|
||||
NSString *s3Path;
|
||||
NSString *localPath;
|
||||
}
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1;
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1;
|
||||
- (id)initWithS3Service:(S3Service *)theS3 s3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1;
|
||||
- (BOOL)makeLocal:(NSError **)error;
|
||||
- (NSArray *)allPackIndexEntries:(NSError **)error;
|
||||
- (PackIndexEntry *)entryForSHA1:(NSString *)sha1 error:(NSError **)error;
|
||||
@end
|
||||
300
DiskPackIndex.m
Normal file
300
DiskPackIndex.m
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#import "DiskPackIndex.h"
|
||||
#import "NSString_extra.h"
|
||||
#import "SetNSError.h"
|
||||
#import "BinarySHA1.h"
|
||||
#import "PackIndexEntry.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "S3Service.h"
|
||||
#import "PackSetSet.h"
|
||||
#import "FileOutputStream.h"
|
||||
#import "Streams.h"
|
||||
#import "NSFileManager_extra.h"
|
||||
#import "ServerBlob.h"
|
||||
#import "PackSet.h"
|
||||
#import "S3ObjectReceiver.h"
|
||||
#import "DiskPack.h"
|
||||
#import "BlobACL.h"
|
||||
#import "FileInputStreamFactory.h"
|
||||
#import "ArqUserLibrary.h"
|
||||
#import "Blob.h"
|
||||
|
||||
typedef struct index_object {
|
||||
uint64_t nbo_offset;
|
||||
uint64_t nbo_datalength;
|
||||
unsigned char sha1[20];
|
||||
unsigned char filler[4];
|
||||
} index_object;
|
||||
|
||||
typedef struct pack_index {
|
||||
uint32_t magic_number;
|
||||
uint32_t nbo_version;
|
||||
uint32_t nbo_fanout[256];
|
||||
index_object first_index_object;
|
||||
} pack_index;
|
||||
|
||||
@interface DiskPackIndex (internal)
|
||||
- (BOOL)savePackIndex:(ServerBlob *)sb bytesWritten:(unsigned long long *)written error:(NSError **)error;
|
||||
- (PackIndexEntry *)doEntryForSHA1:(NSString *)sha1 error:(NSError **)error;
|
||||
- (PackIndexEntry *)findEntryForSHA1:(NSString *)sha1 fd:(int)fd betweenStartIndex:(uint32_t)startIndex andEndIndex:(uint32_t)endIndex error:(NSError **)error;
|
||||
- (BOOL)readFanoutStartIndex:(uint32_t *)start fanoutEndIndex:(uint32_t *)end fromFD:(int)fd forSHA1FirstByte:(unsigned int)firstByte error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation DiskPackIndex
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1 {
|
||||
return [NSString stringWithFormat:@"%@/%@.index", [PackSet s3PathWithS3BucketName:theS3BucketName computerUUID:theComputerUUID packSetName:thePackSetName], thePackSHA1];
|
||||
}
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1 {
|
||||
return [NSString stringWithFormat:@"%@/%@/%@.index", [PackSet localPathWithComputerUUID:theComputerUUID packSetName:thePackSetName], [thePackSHA1 substringToIndex:2], [thePackSHA1 substringFromIndex:2]];
|
||||
}
|
||||
- (id)initWithS3Service:(S3Service *)theS3 s3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName packSHA1:(NSString *)thePackSHA1 {
|
||||
if (self = [super init]) {
|
||||
s3 = [theS3 retain];
|
||||
s3BucketName = [theS3BucketName retain];
|
||||
computerUUID = [theComputerUUID retain];
|
||||
packSetName = [thePackSetName retain];
|
||||
packSHA1 = [thePackSHA1 retain];
|
||||
s3Path = [[DiskPackIndex s3PathWithS3BucketName:s3BucketName computerUUID:computerUUID packSetName:packSetName packSHA1:packSHA1] retain];
|
||||
localPath = [[DiskPackIndex localPathWithComputerUUID:computerUUID packSetName:packSetName packSHA1:packSHA1] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[s3 release];
|
||||
[s3BucketName release];
|
||||
[computerUUID release];
|
||||
[packSetName release];
|
||||
[packSHA1 release];
|
||||
[s3Path release];
|
||||
[localPath release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)makeLocal:(NSError **)error {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
BOOL ret = NO;
|
||||
if (![fm fileExistsAtPath:localPath]) {
|
||||
HSLogDebug(@"packset %@: making pack index %@ local", packSetName, packSHA1);
|
||||
ServerBlob *sb = [s3 newServerBlobAtPath:s3Path error:error];
|
||||
if (sb != nil) {
|
||||
unsigned long long bytesWritten;
|
||||
ret = [self savePackIndex:sb bytesWritten:&bytesWritten error:error];
|
||||
[sb release];
|
||||
} else {
|
||||
HSLogError(@"failed to read pack index from S3 path %@", s3Path);
|
||||
}
|
||||
} else {
|
||||
ret = YES;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (NSArray *)allPackIndexEntries:(NSError **)error {
|
||||
int fd = open([localPath fileSystemRepresentation], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s: %@", strerror(errno), localPath);
|
||||
return nil;
|
||||
}
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"fstat(%@): %s", localPath, strerror(errno));
|
||||
close(fd);
|
||||
return nil;
|
||||
}
|
||||
pack_index *the_pack_index = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (the_pack_index == MAP_FAILED) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"mmap: %s", strerror(errno));
|
||||
close(fd);
|
||||
return NO;
|
||||
}
|
||||
NSMutableArray *ret = [NSMutableArray array];
|
||||
uint32_t count = OSSwapBigToHostInt32(the_pack_index->nbo_fanout[255]);
|
||||
index_object *indexObjects = &(the_pack_index->first_index_object);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
uint64_t offset = OSSwapBigToHostInt64(indexObjects[i].nbo_offset);
|
||||
uint64_t dataLength = OSSwapBigToHostInt64(indexObjects[i].nbo_datalength);
|
||||
NSString *objectSHA1 = [NSString hexStringWithBytes:indexObjects[i].sha1 length:20];
|
||||
PackIndexEntry *pie = [[PackIndexEntry alloc] initWithPackSHA1:packSHA1 offset:offset dataLength:dataLength objectSHA1:objectSHA1];
|
||||
[ret addObject:pie];
|
||||
[pie release];
|
||||
}
|
||||
if (munmap(the_pack_index, st.st_size) == -1) {
|
||||
HSLogError(@"munmap: %s", strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
- (PackIndexEntry *)entryForSHA1:(NSString *)sha1 error:(NSError **)error {
|
||||
if (error != NULL) {
|
||||
*error = nil;
|
||||
}
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
PackIndexEntry *ret = [self doEntryForSHA1:sha1 error:error];
|
||||
[ret retain];
|
||||
if (ret == nil && error != NULL) {
|
||||
[*error retain];
|
||||
}
|
||||
[pool drain];
|
||||
[ret autorelease];
|
||||
if (ret == nil && error != NULL) {
|
||||
[*error autorelease];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DiskPackIndex (internal)
|
||||
- (BOOL)savePackIndex:(ServerBlob *)sb bytesWritten:(unsigned long long *)written error:(NSError **)error {
|
||||
if (![[NSFileManager defaultManager] ensureParentPathExistsForPath:localPath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
id <InputStream> is = [sb newInputStream];
|
||||
NSError *myError = nil;
|
||||
BOOL ret = [Streams transferFrom:is atomicallyToFile:localPath bytesWritten:written error:&myError];
|
||||
if (ret) {
|
||||
HSLogDebug(@"wrote %qu bytes to %@", *written, localPath);
|
||||
} else {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
HSLogError(@"error making pack %@ local at %@: %@", packSHA1, localPath, [myError localizedDescription]);
|
||||
}
|
||||
[is release];
|
||||
return ret;
|
||||
}
|
||||
- (PackIndexEntry *)doEntryForSHA1:(NSString *)sha1 error:(NSError **)error {
|
||||
NSData *sha1Hex = [sha1 hexStringToData];
|
||||
unsigned char *sha1Bytes = (unsigned char *)[sha1Hex bytes];
|
||||
HSLogTrace(@"looking for sha1 %@ in packindex %@", sha1, packSHA1);
|
||||
int fd = open([localPath fileSystemRepresentation], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s: %@", strerror(errno), localPath);
|
||||
return nil;
|
||||
}
|
||||
uint32_t startIndex;
|
||||
uint32_t endIndex;
|
||||
if (![self readFanoutStartIndex:&startIndex fanoutEndIndex:&endIndex fromFD:fd forSHA1FirstByte:(unsigned int)sha1Bytes[0] error:error]) {
|
||||
close(fd);
|
||||
return nil;
|
||||
}
|
||||
close(fd);
|
||||
if (endIndex == 0) {
|
||||
SETNSERROR(@"PacksErrorDomain", ERROR_NOT_FOUND, @"sha1 %@ not found in pack", sha1);
|
||||
return NO;
|
||||
}
|
||||
fd = open([localPath fileSystemRepresentation], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s: %@", strerror(errno), localPath);
|
||||
return nil;
|
||||
}
|
||||
PackIndexEntry *ret = [self findEntryForSHA1:sha1 fd:fd betweenStartIndex:startIndex andEndIndex:endIndex error:error];
|
||||
close(fd);
|
||||
if (ret != nil) {
|
||||
HSLogTrace(@"found sha1 %@ in packindex %@", sha1, packSHA1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (PackIndexEntry *)findEntryForSHA1:(NSString *)sha1 fd:(int)fd betweenStartIndex:(uint32_t)startIndex andEndIndex:(uint32_t)endIndex error:(NSError **)error {
|
||||
NSData *sha1Data = [sha1 hexStringToData];
|
||||
const void *sha1Bytes = [sha1Data bytes];
|
||||
uint32_t lengthToMap = 4 + 4 + 256*4 + endIndex * sizeof(index_object);
|
||||
pack_index *the_pack_index = mmap(0, lengthToMap, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (the_pack_index == MAP_FAILED) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"mmap: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
int64_t left = startIndex;
|
||||
int64_t right = endIndex - 1;
|
||||
int64_t middle;
|
||||
int64_t offset;
|
||||
int64_t dataLength;
|
||||
PackIndexEntry *pie = nil;
|
||||
while (left <= right) {
|
||||
middle = (left + right)/2;
|
||||
index_object *firstIndexObject = &(the_pack_index->first_index_object);
|
||||
index_object *middleIndexObject = &firstIndexObject[middle];
|
||||
void *middleSHA1 = middleIndexObject->sha1;
|
||||
NSComparisonResult result = [BinarySHA1 compare:middleSHA1 to:sha1Bytes];
|
||||
switch (result) {
|
||||
case NSOrderedAscending:
|
||||
left = middle + 1;
|
||||
break;
|
||||
case NSOrderedDescending:
|
||||
right = middle - 1;
|
||||
break;
|
||||
default:
|
||||
offset = OSSwapBigToHostInt64(middleIndexObject->nbo_offset);
|
||||
dataLength = OSSwapBigToHostInt64(middleIndexObject->nbo_datalength);
|
||||
pie = [[[PackIndexEntry alloc] initWithPackSHA1:packSHA1 offset:offset dataLength:dataLength objectSHA1:sha1] autorelease];
|
||||
}
|
||||
if (pie != nil) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (munmap(the_pack_index, lengthToMap) == -1) {
|
||||
HSLogError(@"munmap: %s", strerror(errno));
|
||||
}
|
||||
if (pie == nil) {
|
||||
SETNSERROR(@"PackErrorDomain", ERROR_NOT_FOUND, @"sha1 %@ not found in pack %@", sha1, packSHA1);
|
||||
}
|
||||
return pie;
|
||||
}
|
||||
- (BOOL)readFanoutStartIndex:(uint32_t *)start fanoutEndIndex:(uint32_t *)end fromFD:(int)fd forSHA1FirstByte:(unsigned int)firstByte error:(NSError **)error {
|
||||
size_t len = 4 + 4 + 4*256;
|
||||
uint32_t *map = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (map == MAP_FAILED) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"mmap: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
BOOL ret = YES;
|
||||
uint32_t magicNumber = OSSwapBigToHostInt32(map[0]);
|
||||
uint32_t version = OSSwapBigToHostInt32(map[1]);
|
||||
if (magicNumber != 0xff744f63 || version != 2) {
|
||||
SETNSERROR(@"PackErrorDomain", -1, @"invalid pack index header");
|
||||
ret = NO;
|
||||
} else {
|
||||
uint32_t *fanoutTable = map + 2;
|
||||
*start = 0;
|
||||
if (firstByte > 0) {
|
||||
*start = OSSwapBigToHostInt32(fanoutTable[firstByte - 1]);
|
||||
}
|
||||
*end = OSSwapBigToHostInt32(fanoutTable[firstByte]);
|
||||
}
|
||||
if (munmap(map, len) == -1) {
|
||||
HSLogError(@"munmap: %s", strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
91
FileAttributes.h
Normal file
91
FileAttributes.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface FileAttributes : NSObject {
|
||||
BOOL targetExists;
|
||||
NSString *path;
|
||||
const char *cPath;
|
||||
struct stat st;
|
||||
struct timespec createTime;
|
||||
NSString *aclString;
|
||||
int finderFlags;
|
||||
int extendedFinderFlags;
|
||||
NSString *finderFileType;
|
||||
NSString *finderFileCreator;
|
||||
}
|
||||
- (id)initWithPath:(NSString *)thePath error:(NSError **)error;
|
||||
- (id)initWithPath:(NSString *)thePath stat:(struct stat *)st error:(NSError **)error;
|
||||
|
||||
- (unsigned long long)fileSize;
|
||||
- (NSString *)aclString;
|
||||
- (NSString *)aclSHA1;
|
||||
- (int)uid;
|
||||
- (int)gid;
|
||||
- (int)mode;
|
||||
- (long)mtime_sec;
|
||||
- (long)mtime_nsec;
|
||||
- (long)flags;
|
||||
- (int)finderFlags;
|
||||
- (int)extendedFinderFlags;
|
||||
- (NSString *)finderFileType;
|
||||
- (NSString *)finderFileCreator;
|
||||
- (BOOL)isExtensionHidden;
|
||||
- (BOOL)isFifo;
|
||||
- (BOOL)isDevice;
|
||||
- (BOOL)isSymbolicLink;
|
||||
- (BOOL)isRegularFile;
|
||||
- (BOOL)isSocket;
|
||||
- (int)st_dev;
|
||||
- (int)st_ino;
|
||||
- (uint32_t)st_nlink;
|
||||
- (int)st_rdev;
|
||||
- (int64_t)ctime_sec;
|
||||
- (int64_t)ctime_nsec;
|
||||
- (int64_t)createTime_sec;
|
||||
- (int64_t)createTime_nsec;
|
||||
- (int64_t)st_blocks;
|
||||
- (uint32_t)st_blksize;
|
||||
|
||||
- (BOOL)applyFinderFileType:(NSString *)finderFileType finderFileCreator:(NSString *)finderFileCreator error:(NSError **)error;
|
||||
- (BOOL)applyFlags:(int)flags error:(NSError **)error;
|
||||
- (BOOL)applyAcl:(NSString *)aclString error:(NSError **)error;
|
||||
- (BOOL)applyFinderFlags:(int)finderFlags error:(NSError **)error;
|
||||
- (BOOL)applyExtendedFinderFlags:(int)extendedFinderFlags error:(NSError **)error;
|
||||
- (BOOL)applyExtensionHidden:(BOOL)isExtensionHidden error:(NSError **)error;
|
||||
- (BOOL)applyUID:(int)uid gid:(int)gid error:(NSError **)error;
|
||||
- (BOOL)applyMode:(int)mode error:(NSError **)error;
|
||||
- (BOOL)applyMTimeSec:(int64_t)mtime_sec mTimeNSec:(int64_t)mtime_nsec error:(NSError **)error;
|
||||
- (BOOL)applyCreateTimeSec:(int64_t)createTime_sec createTimeNSec:(int64_t)createTime_sec error:(NSError **)error;
|
||||
@end
|
||||
559
FileAttributes.m
Normal file
559
FileAttributes.m
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <sys/attr.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#import "FileAttributes.h"
|
||||
#import "SHA1Hash.h"
|
||||
#import "FileACL.h"
|
||||
#import "SetNSError.h"
|
||||
#import "OSStatusDescription.h"
|
||||
|
||||
#define kCouldNotCreateCFString 4
|
||||
#define kCouldNotGetStringData 5
|
||||
#define MAX_PATH 1024
|
||||
|
||||
struct createDateBuf {
|
||||
u_int32_t length;
|
||||
struct timespec createTime;
|
||||
};
|
||||
|
||||
static OSStatus ConvertCStringToHFSUniStr(const char* cStr, HFSUniStr255 *uniStr) {
|
||||
OSStatus oss = noErr;
|
||||
CFStringRef tmpStringRef = CFStringCreateWithCString(kCFAllocatorDefault, cStr, kCFStringEncodingMacRoman);
|
||||
if (tmpStringRef != NULL) {
|
||||
if (CFStringGetCString(tmpStringRef, (char*)uniStr->unicode, sizeof(uniStr->unicode), kCFStringEncodingUnicode)) {
|
||||
uniStr->length = CFStringGetLength(tmpStringRef);
|
||||
} else {
|
||||
oss = kCouldNotGetStringData;
|
||||
}
|
||||
CFRelease(tmpStringRef);
|
||||
} else {
|
||||
oss = kCouldNotCreateCFString;
|
||||
}
|
||||
return oss;
|
||||
}
|
||||
static OSStatus SymlinkPathMakeRef(const UInt8 *path, FSRef *ref, Boolean *isDirectory) {
|
||||
FSRef tmpFSRef;
|
||||
char tmpPath[MAX_PATH];
|
||||
char *tmpNamePtr;
|
||||
OSStatus oss;
|
||||
|
||||
strcpy(tmpPath, (char *)path);
|
||||
tmpNamePtr = strrchr(tmpPath, '/');
|
||||
if (*(tmpNamePtr + 1) == '\0') {
|
||||
// Last character in the path is a '/'.
|
||||
*tmpNamePtr = '\0';
|
||||
tmpNamePtr = strrchr(tmpPath, '/');
|
||||
}
|
||||
*tmpNamePtr = '\0';
|
||||
tmpNamePtr++;
|
||||
|
||||
// Get FSRef for parent directory.
|
||||
oss = FSPathMakeRef((const UInt8 *)tmpPath, &tmpFSRef, NULL);
|
||||
if (oss == noErr) {
|
||||
HFSUniStr255 uniName;
|
||||
oss = ConvertCStringToHFSUniStr(tmpNamePtr, &uniName);
|
||||
if (oss == noErr) {
|
||||
FSRef newFSRef;
|
||||
oss = FSMakeFSRefUnicode(&tmpFSRef, uniName.length, uniName.unicode, kTextEncodingUnknown, &newFSRef);
|
||||
tmpFSRef = newFSRef;
|
||||
}
|
||||
}
|
||||
if (oss == noErr) {
|
||||
*ref = tmpFSRef;
|
||||
}
|
||||
return oss;
|
||||
}
|
||||
|
||||
@implementation FileAttributes
|
||||
- (id)initWithPath:(NSString *)thePath error:(NSError **)error {
|
||||
struct stat theStat;
|
||||
int ret = lstat([thePath fileSystemRepresentation], &theStat);
|
||||
if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s", strerror(errno));
|
||||
return nil;
|
||||
}
|
||||
return [self initWithPath:thePath stat:&theStat error:error];
|
||||
}
|
||||
- (id)initWithPath:(NSString *)thePath stat:(struct stat *)theStat error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
path = [thePath copy];
|
||||
cPath = [path fileSystemRepresentation];
|
||||
memcpy(&st, theStat, sizeof(st));
|
||||
targetExists = YES;
|
||||
if ((st.st_mode & S_IFLNK) == S_IFLNK) {
|
||||
struct stat targetSt;
|
||||
int ret = stat(cPath, &targetSt);
|
||||
if (ret == -1 && errno == ENOENT) {
|
||||
targetExists = NO;
|
||||
}
|
||||
}
|
||||
if (targetExists) {
|
||||
FSRef fsRef;
|
||||
Boolean isDirectory;
|
||||
OSStatus oss = 0;
|
||||
if ((st.st_mode & S_IFLNK) == S_IFLNK) {
|
||||
oss = SymlinkPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
} else {
|
||||
oss = FSPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
}
|
||||
if (oss == bdNamErr) {
|
||||
HSLogInfo(@"skipping finder flags for %s: %@", cPath, [OSStatusDescription descriptionForMacOSStatus:oss]);
|
||||
}else if (oss != noErr) {
|
||||
SETNSERROR(@"MacFilesErrorDomain", oss, @"%@", [OSStatusDescription descriptionForMacOSStatus:oss]);
|
||||
[self release];
|
||||
self = nil;
|
||||
return self;
|
||||
} else {
|
||||
FSCatalogInfo catalogInfo;
|
||||
OSErr oserr = FSGetCatalogInfo(&fsRef, kFSCatInfoCreateDate | kFSCatInfoFinderInfo | kFSCatInfoFinderXInfo, &catalogInfo, NULL, NULL, NULL);
|
||||
if (oserr) {
|
||||
SETNSERROR(@"MacFilesErrorDomain", oss, @"%@", [OSStatusDescription descriptionForMacOSStatus:(OSStatus)oserr]);
|
||||
[self release];
|
||||
self = nil;
|
||||
return self;
|
||||
}
|
||||
finderFlags = 0;
|
||||
extendedFinderFlags = 0;
|
||||
if (isDirectory) {
|
||||
FolderInfo *folderInfo = (FolderInfo *)&catalogInfo.finderInfo;
|
||||
finderFlags = folderInfo->finderFlags;
|
||||
ExtendedFolderInfo *extFolderInfo = (ExtendedFolderInfo *)&catalogInfo.extFinderInfo;
|
||||
extendedFinderFlags = extFolderInfo->extendedFinderFlags;
|
||||
finderFileType = [[NSString alloc] initWithString:@""];
|
||||
finderFileCreator = [[NSString alloc] initWithString:@""];
|
||||
} else {
|
||||
FileInfo *fileInfo = (FileInfo *)&catalogInfo.finderInfo;
|
||||
finderFlags = fileInfo->finderFlags;
|
||||
ExtendedFileInfo *extFileInfo = (ExtendedFileInfo *)&catalogInfo.extFinderInfo;
|
||||
extendedFinderFlags = extFileInfo->extendedFinderFlags;
|
||||
|
||||
char fileType[5];
|
||||
fileType[0] = *((const char *)&fileInfo->fileType + 3);
|
||||
fileType[1] = *((const char *)&fileInfo->fileType + 2);
|
||||
fileType[2] = *((const char *)&fileInfo->fileType + 1);
|
||||
fileType[3] = *((const char *)&fileInfo->fileType);
|
||||
fileType[4] = 0;
|
||||
finderFileType = [[NSString alloc] initWithCString:fileType encoding:NSUTF8StringEncoding];
|
||||
char fileCreator[5];
|
||||
fileCreator[0] = *((const char *)&fileInfo->fileCreator + 3);
|
||||
fileCreator[1] = *((const char *)&fileInfo->fileCreator + 2);
|
||||
fileCreator[2] = *((const char *)&fileInfo->fileCreator + 1);
|
||||
fileCreator[3] = *((const char *)&fileInfo->fileCreator);
|
||||
fileCreator[4] = 0;
|
||||
finderFileCreator = [[NSString alloc] initWithCString:fileCreator encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (![FileACL aclText:&aclString forFile:path error:error]) {
|
||||
[self release];
|
||||
self = nil;
|
||||
return self;
|
||||
}
|
||||
[aclString retain];
|
||||
|
||||
struct attrlist attrList;
|
||||
memset(&attrList, 0, sizeof(attrList));
|
||||
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
attrList.commonattr = ATTR_CMN_CRTIME;
|
||||
struct createDateBuf createDateBuf;
|
||||
if (getattrlist(cPath, &attrList, &createDateBuf, sizeof(createDateBuf), FSOPT_NOFOLLOW) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"Error getting create date for %@: %s", thePath, strerror(errno));
|
||||
[self release];
|
||||
self = nil;
|
||||
return self;
|
||||
}
|
||||
createTime.tv_sec = createDateBuf.createTime.tv_sec;
|
||||
createTime.tv_nsec = createDateBuf.createTime.tv_nsec;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[path release];
|
||||
[aclString release];
|
||||
[finderFileType release];
|
||||
[finderFileCreator release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (unsigned long long)fileSize {
|
||||
return (unsigned long long)st.st_size;
|
||||
}
|
||||
- (NSString *)aclString {
|
||||
return aclString;
|
||||
}
|
||||
- (NSString *)aclSHA1 {
|
||||
NSString *sha1 = nil;
|
||||
if (aclString) {
|
||||
sha1 = [SHA1Hash hashData:[aclString dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
return sha1;
|
||||
}
|
||||
- (int)uid {
|
||||
return st.st_uid;
|
||||
}
|
||||
- (int)gid {
|
||||
return st.st_gid;
|
||||
}
|
||||
- (int)mode {
|
||||
return st.st_mode;
|
||||
}
|
||||
- (long)mtime_sec {
|
||||
return st.st_mtimespec.tv_sec;
|
||||
}
|
||||
- (long)mtime_nsec {
|
||||
return st.st_mtimespec.tv_nsec;
|
||||
}
|
||||
- (long)flags {
|
||||
return st.st_flags;
|
||||
}
|
||||
|
||||
- (int)finderFlags {
|
||||
return finderFlags;
|
||||
}
|
||||
- (int)extendedFinderFlags {
|
||||
return extendedFinderFlags;
|
||||
}
|
||||
- (NSString *)finderFileType {
|
||||
return finderFileType;
|
||||
}
|
||||
- (NSString *)finderFileCreator {
|
||||
return finderFileCreator;
|
||||
}
|
||||
- (BOOL)isExtensionHidden {
|
||||
return (st.st_flags & UF_HIDDEN) == UF_HIDDEN;
|
||||
}
|
||||
- (BOOL)isFifo {
|
||||
return (st.st_mode & S_IFIFO) == S_IFIFO;
|
||||
}
|
||||
- (BOOL)isDevice {
|
||||
return (st.st_mode & S_IFCHR) == S_IFCHR || (st.st_mode & S_IFBLK) == S_IFBLK;
|
||||
}
|
||||
- (BOOL)isSymbolicLink {
|
||||
return (st.st_mode & S_IFLNK) == S_IFLNK;
|
||||
}
|
||||
- (BOOL)isRegularFile {
|
||||
return (st.st_mode & S_IFREG) == S_IFREG;
|
||||
}
|
||||
- (BOOL)isSocket {
|
||||
return (st.st_mode & S_IFSOCK) == S_IFSOCK;
|
||||
}
|
||||
- (int)st_dev {
|
||||
return st.st_dev;
|
||||
}
|
||||
- (int)st_ino {
|
||||
return st.st_ino;
|
||||
}
|
||||
- (uint32_t)st_nlink {
|
||||
return st.st_nlink;
|
||||
}
|
||||
- (int)st_rdev {
|
||||
return st.st_rdev;
|
||||
}
|
||||
- (int64_t)ctime_sec {
|
||||
return st.st_ctimespec.tv_sec;
|
||||
}
|
||||
- (int64_t)ctime_nsec {
|
||||
return st.st_ctimespec.tv_nsec;
|
||||
}
|
||||
- (int64_t)createTime_sec {
|
||||
return createTime.tv_sec;
|
||||
}
|
||||
- (int64_t)createTime_nsec {
|
||||
return createTime.tv_nsec;
|
||||
}
|
||||
- (int64_t)st_blocks {
|
||||
return st.st_blocks;
|
||||
}
|
||||
- (uint32_t)st_blksize {
|
||||
return st.st_blksize;
|
||||
}
|
||||
- (BOOL)applyFinderFileType:(NSString *)fft finderFileCreator:(NSString *)ffc error:(NSError **)error {
|
||||
if (targetExists && (![fft isEqualToString:finderFileType] || ![ffc isEqualToString:finderFileCreator])) {
|
||||
if ([fft length] != 4) {
|
||||
HSLogWarn(@"not applying finder file type '%@' to %@: invalid length (must be 4 characters)", fft, path);
|
||||
} else if ([ffc length] != 4) {
|
||||
HSLogWarn(@"not applying finder file type '%@' to %@: invalid length (must be 4 characters)", ffc, path);
|
||||
} else {
|
||||
FSRef fsRef;
|
||||
Boolean isDirectory;
|
||||
OSStatus oss = 0;
|
||||
if ((st.st_mode & S_IFLNK) == S_IFLNK) {
|
||||
oss = SymlinkPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
} else {
|
||||
oss = FSPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
}
|
||||
if (oss != noErr) {
|
||||
if (oss == bdNamErr) {
|
||||
HSLogInfo(@"not setting finder file type/creator on %s: bad name", cPath);
|
||||
return YES;
|
||||
} else {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:oss]);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
if (isDirectory) {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"cannot apply finderFileType to a directory");
|
||||
return NO;
|
||||
}
|
||||
|
||||
FSCatalogInfo catalogInfo;
|
||||
OSErr oserr = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL);
|
||||
if (oserr) {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:(OSStatus)oserr]);
|
||||
return NO;
|
||||
}
|
||||
FileInfo *fileInfo = (FileInfo *)&catalogInfo.finderInfo;
|
||||
const char *fileType = [fft UTF8String];
|
||||
char *destFileType = (char *)&fileInfo->fileType;
|
||||
destFileType[3] = fileType[0];
|
||||
destFileType[2] = fileType[1];
|
||||
destFileType[1] = fileType[2];
|
||||
destFileType[0] = fileType[3];
|
||||
|
||||
const char *fileCreator = [ffc UTF8String];
|
||||
char *destFileCreator = (char *)&fileInfo->fileCreator;
|
||||
destFileCreator[3] = fileCreator[0];
|
||||
destFileCreator[2] = fileCreator[1];
|
||||
destFileCreator[1] = fileCreator[2];
|
||||
destFileCreator[0] = fileCreator[3];
|
||||
|
||||
oserr = FSSetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo);
|
||||
if (oserr) {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:(OSStatus)oserr]);
|
||||
return NO;
|
||||
}
|
||||
[finderFileType release];
|
||||
finderFileType = [fft copy];
|
||||
[finderFileCreator release];
|
||||
finderFileCreator = [ffc copy];
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyFlags:(int)flags error:(NSError **)error {
|
||||
if (targetExists && flags != st.st_flags) {
|
||||
HSLogTrace(@"chflags(%s, %d)", cPath, flags);
|
||||
if (chflags(cPath, flags) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"chflags: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
st.st_flags = flags;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyAcl:(NSString *)theACLString error:(NSError **)error {
|
||||
BOOL ret = YES;
|
||||
if (![theACLString isEqualToString:aclString]) {
|
||||
ret = [FileACL writeACLText:theACLString toFile:path error:error];
|
||||
if (ret) {
|
||||
[aclString release];
|
||||
aclString = [theACLString retain];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)applyFinderFlags:(int)ff error:(NSError **)error {
|
||||
if (targetExists && ff != finderFlags) {
|
||||
FSRef fsRef;
|
||||
Boolean isDirectory;
|
||||
OSStatus oss = 0;
|
||||
if ((st.st_mode & S_IFLNK) == S_IFLNK) {
|
||||
oss = SymlinkPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
} else {
|
||||
oss = FSPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
}
|
||||
if (oss != noErr) {
|
||||
if (oss == bdNamErr) {
|
||||
HSLogInfo(@"not setting finder file type/creator on %s: bad name", cPath);
|
||||
return YES;
|
||||
} else {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:oss]);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
FSCatalogInfo catalogInfo;
|
||||
OSErr oserr = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL);
|
||||
if (oserr) {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:(OSStatus)oserr]);
|
||||
return NO;
|
||||
}
|
||||
if (isDirectory) {
|
||||
FolderInfo *folderInfo = (FolderInfo *)&catalogInfo.finderInfo;
|
||||
folderInfo->finderFlags = ff;
|
||||
} else {
|
||||
FileInfo *fileInfo = (FileInfo *)&catalogInfo.finderInfo;
|
||||
fileInfo->finderFlags = ff;
|
||||
}
|
||||
oserr = FSSetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo);
|
||||
if (oserr) {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:(OSStatus)oserr]);
|
||||
return NO;
|
||||
}
|
||||
finderFlags = ff;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyExtendedFinderFlags:(int)eff error:(NSError **)error {
|
||||
if (targetExists && extendedFinderFlags != eff) {
|
||||
FSRef fsRef;
|
||||
Boolean isDirectory;
|
||||
OSStatus oss = 0;
|
||||
if ((st.st_mode & S_IFLNK) == S_IFLNK) {
|
||||
oss = SymlinkPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
} else {
|
||||
oss = FSPathMakeRef((UInt8*)cPath, &fsRef, &isDirectory);
|
||||
}
|
||||
if (oss != noErr) {
|
||||
if (oss == bdNamErr) {
|
||||
HSLogInfo(@"not setting finder file type/creator on %s: bad name", cPath);
|
||||
return YES;
|
||||
} else {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:oss]);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
FSCatalogInfo catalogInfo;
|
||||
OSErr oserr = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderXInfo, &catalogInfo, NULL, NULL, NULL);
|
||||
if (oserr) {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:(OSStatus)oserr]);
|
||||
return NO;
|
||||
}
|
||||
if (isDirectory) {
|
||||
ExtendedFolderInfo *extFolderInfo = (ExtendedFolderInfo *)&catalogInfo.extFinderInfo;
|
||||
extFolderInfo->extendedFinderFlags = eff;
|
||||
} else {
|
||||
ExtendedFileInfo *extFileInfo = (ExtendedFileInfo *)&catalogInfo.extFinderInfo;
|
||||
extFileInfo->extendedFinderFlags = eff;
|
||||
}
|
||||
oserr = FSSetCatalogInfo(&fsRef, kFSCatInfoFinderXInfo, &catalogInfo);
|
||||
if (oserr) {
|
||||
SETNSERROR(@"FileManagerErrorDomain", -1, @"%@", [OSStatusDescription descriptionForMacOSStatus:(OSStatus)oserr]);
|
||||
return NO;
|
||||
}
|
||||
extendedFinderFlags = eff;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyExtensionHidden:(BOOL)hidden error:(NSError **)error {
|
||||
BOOL ret = YES;
|
||||
if (hidden != [self isExtensionHidden]) {
|
||||
NSDictionary *attribs = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:hidden], NSFileExtensionHidden, nil];
|
||||
ret = [[NSFileManager defaultManager] setAttributes:attribs ofItemAtPath:path error:error];
|
||||
if (ret) {
|
||||
if (hidden) {
|
||||
st.st_flags = st.st_flags & UF_HIDDEN;
|
||||
} else {
|
||||
st.st_flags = st.st_flags & (0xffffffff ^ UF_HIDDEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)applyUID:(int)uid gid:(int)gid error:(NSError **)error {
|
||||
if (uid != st.st_uid || gid != st.st_gid) {
|
||||
HSLogTrace(@"lchown(%s, %d, %d)", cPath, uid, gid);
|
||||
if (lchown(cPath, uid, gid) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"lchown: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
st.st_uid = uid;
|
||||
st.st_gid = gid;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyMode:(int)mode error:(NSError **)error {
|
||||
if (mode != st.st_mode) {
|
||||
if ((st.st_mode & S_IFDIR) == S_IFDIR) {
|
||||
HSLogTrace(@"chmod(%s, %d)", cPath, mode);
|
||||
int ret = chmod(cPath, mode);
|
||||
if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"Setting permissions on %@: %s", path, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
int fd = open(cPath, O_RDWR|O_SYMLINK);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
HSLogTrace(@"fchmod symlink (%s, %d)", cPath, mode);
|
||||
int ret = fchmod(fd, mode);
|
||||
close(fd);
|
||||
if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"Setting permissions on %@: %s", path, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
st.st_mode = mode;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyMTimeSec:(int64_t)mtime_sec mTimeNSec:(int64_t)mtime_nsec error:(NSError **)error {
|
||||
if (st.st_mtimespec.tv_sec != mtime_sec
|
||||
|| st.st_mtimespec.tv_nsec != mtime_nsec) {
|
||||
struct timespec mtimeSpec = { mtime_sec, mtime_nsec };
|
||||
struct timeval atimeVal;
|
||||
struct timeval mtimeVal;
|
||||
TIMESPEC_TO_TIMEVAL(&atimeVal, &mtimeSpec); // Just use mtime because we don't have atime, nor do we care about atime.
|
||||
TIMESPEC_TO_TIMEVAL(&mtimeVal, &mtimeSpec);
|
||||
struct timeval timevals[2];
|
||||
timevals[0] = atimeVal;
|
||||
timevals[1] = mtimeVal;
|
||||
if (utimes(cPath, timevals) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"utimes(%@): %s", path, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyCreateTimeSec:(int64_t)theCreateTime_sec createTimeNSec:(int64_t)theCreateTime_nsec error:(NSError **)error {
|
||||
if (createTime.tv_sec != theCreateTime_sec || createTime.tv_nsec != theCreateTime_nsec) {
|
||||
createTime.tv_sec = theCreateTime_sec;
|
||||
createTime.tv_nsec = theCreateTime_nsec;
|
||||
|
||||
struct attrlist attrList;
|
||||
memset(&attrList, 0, sizeof(attrList));
|
||||
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
attrList.commonattr = ATTR_CMN_CRTIME;
|
||||
if (setattrlist(cPath, &attrList, &createTime, sizeof(createTime), FSOPT_NOFOLLOW) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"Error setting create date on %@: %s", path, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
53
HSLog.h
Normal file
53
HSLog.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
extern unsigned int global_hslog_level;
|
||||
|
||||
extern void setHSLogLevel(int level);
|
||||
extern int hsLogLevelForName(NSString *levelName);
|
||||
extern NSString *nameForHSLogLevel(int level);
|
||||
#define HSLOG_LEVEL_TRACE (5)
|
||||
#define HSLOG_LEVEL_DEBUG (4)
|
||||
#define HSLOG_LEVEL_INFO (3)
|
||||
#define HSLOG_LEVEL_WARN (2)
|
||||
#define HSLOG_LEVEL_ERROR (1)
|
||||
#define HSLOG_LEVEL_NONE (0)
|
||||
|
||||
#define HSLogTrace( s, ... ) { if (global_hslog_level >= HSLOG_LEVEL_TRACE) { NSLog(@"TRACE [thread %x] %p %@:%d %@", pthread_mach_thread_np(pthread_self()), self, [@__FILE__ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__]); } }
|
||||
#define HSLogDebug( s, ... ) { if (global_hslog_level >= HSLOG_LEVEL_DEBUG) { NSLog(@"DEBUG [thread %x] %p %@:%d %@", pthread_mach_thread_np(pthread_self()), self, [@__FILE__ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__]); } }
|
||||
#define HSLogDebugStatic( s, ... ) { if (global_hslog_level >= HSLOG_LEVEL_DEBUG) { NSLog(@"DEBUG [thread %x] %@:%d %@", pthread_mach_thread_np(pthread_self()), [@__FILE__ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__]); } }
|
||||
#define HSLogInfo( s, ... ) { if (global_hslog_level >= HSLOG_LEVEL_INFO) { NSLog(@"INFO [thread %x] %@", pthread_mach_thread_np(pthread_self()), [NSString stringWithFormat:(s), ##__VA_ARGS__]); } }
|
||||
#define HSLogWarn( s, ... ) { if (global_hslog_level >= HSLOG_LEVEL_WARN) { NSLog(@"WARN [thread %x] %@", pthread_mach_thread_np(pthread_self()), [NSString stringWithFormat:(s), ##__VA_ARGS__]); } }
|
||||
#define HSLogError( s, ... ) { if (global_hslog_level >= HSLOG_LEVEL_ERROR) { NSLog(@"ERROR [thread %x] %@", pthread_mach_thread_np(pthread_self()), [NSString stringWithFormat:(s), ##__VA_ARGS__]); } }
|
||||
#define HSLog( s, ... ) NSLog(@"%@", [NSString stringWithFormat:(s), ##__VA_ARGS__])
|
||||
68
HSLog.m
Normal file
68
HSLog.m
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "HSLog.h"
|
||||
|
||||
unsigned int global_hslog_level = HSLOG_LEVEL_WARN;
|
||||
|
||||
void setHSLogLevel(int level) {
|
||||
global_hslog_level = level;
|
||||
}
|
||||
extern int hsLogLevelForName(NSString *levelName) {
|
||||
if ([[levelName lowercaseString] isEqualToString:@"error"]) {
|
||||
return HSLOG_LEVEL_ERROR;
|
||||
} else if ([[levelName lowercaseString] isEqualToString:@"warn"]) {
|
||||
return HSLOG_LEVEL_WARN;
|
||||
} else if ([[levelName lowercaseString] isEqualToString:@"info"]) {
|
||||
return HSLOG_LEVEL_INFO;
|
||||
} else if ([[levelName lowercaseString] isEqualToString:@"debug"]) {
|
||||
return HSLOG_LEVEL_DEBUG;
|
||||
} else if ([[levelName lowercaseString] isEqualToString:@"trace"]) {
|
||||
return HSLOG_LEVEL_TRACE;
|
||||
}
|
||||
return HSLOG_LEVEL_NONE;
|
||||
}
|
||||
extern NSString *nameForHSLogLevel(int level) {
|
||||
switch (level) {
|
||||
case HSLOG_LEVEL_ERROR:
|
||||
return @"Error";
|
||||
case HSLOG_LEVEL_WARN:
|
||||
return @"Warn";
|
||||
case HSLOG_LEVEL_INFO:
|
||||
return @"Info";
|
||||
case HSLOG_LEVEL_DEBUG:
|
||||
return @"Debug";
|
||||
case HSLOG_LEVEL_TRACE:
|
||||
return @"Trace";
|
||||
}
|
||||
return @"none";
|
||||
}
|
||||
104
Node.h
Normal file
104
Node.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class MutableS3Repo;
|
||||
#import "InputStream.h"
|
||||
#import "InputStreamFactory.h"
|
||||
#import "OutputStream.h"
|
||||
|
||||
@interface Node : NSObject {
|
||||
int treeVersion;
|
||||
BOOL isTree;
|
||||
unsigned long long dataSize;
|
||||
NSMutableArray *dataSHA1s;
|
||||
NSString *thumbnailSHA1;
|
||||
NSString *previewSHA1;
|
||||
NSString *xattrsSHA1;
|
||||
unsigned long long xattrsSize;
|
||||
NSString *aclSHA1;
|
||||
int uid;
|
||||
int gid;
|
||||
int mode;
|
||||
int64_t mtime_sec;
|
||||
int64_t mtime_nsec;
|
||||
long long flags;
|
||||
int finderFlags;
|
||||
int extendedFinderFlags;
|
||||
NSString *finderFileType;
|
||||
NSString *finderFileCreator;
|
||||
BOOL isFileExtensionHidden;
|
||||
int st_dev;
|
||||
int st_ino;
|
||||
uint32_t st_nlink; // in struct stat, it's only 16 bits.
|
||||
int st_rdev;
|
||||
int64_t ctime_sec;
|
||||
int64_t ctime_nsec;
|
||||
int64_t createTime_sec;
|
||||
int64_t createTime_nsec;
|
||||
int64_t st_blocks;
|
||||
uint32_t st_blksize;
|
||||
}
|
||||
- (id)initWithInputStream:(id <InputStream>)is treeVersion:(int)theTreeVersion error:(NSError **)error;
|
||||
- (void)writeToData:(NSMutableData *)data;
|
||||
- (BOOL)dataMatchesStatData:(struct stat *)st;
|
||||
|
||||
@property(readonly) BOOL isTree;
|
||||
@property(readonly,copy) NSString *treeSHA1;
|
||||
@property(readonly,copy) NSArray *dataSHA1s;
|
||||
|
||||
@property(readonly) unsigned long long dataSize;
|
||||
@property(readonly,copy) NSString *thumbnailSHA1;
|
||||
@property(readonly,copy) NSString *previewSHA1;
|
||||
@property(readonly,copy) NSString *xattrsSHA1;
|
||||
@property(readonly) unsigned long long xattrsSize;
|
||||
@property(readonly,copy) NSString *aclSHA1;
|
||||
@property(readonly) int uid;
|
||||
@property(readonly) int gid;
|
||||
@property(readonly) int mode;
|
||||
@property(readonly) long long mtime_sec;
|
||||
@property(readonly) long long mtime_nsec;
|
||||
@property(readonly) long long flags;
|
||||
@property(readonly) int finderFlags;
|
||||
@property(readonly) int extendedFinderFlags;
|
||||
@property(readonly,copy) NSString *finderFileType;
|
||||
@property(readonly,copy) NSString *finderFileCreator;
|
||||
@property(readonly) BOOL isFileExtensionHidden;
|
||||
@property(readonly) int treeVersion;
|
||||
@property(readonly) int st_rdev;
|
||||
@property(readonly) long long ctime_sec;
|
||||
@property(readonly) long long ctime_nsec;
|
||||
@property(readonly) long long createTime_sec;
|
||||
@property(readonly) long long createTime_nsec;
|
||||
@property(readonly) uint32_t st_nlink;
|
||||
@property(readonly) int st_ino;
|
||||
@end
|
||||
165
Node.m
Normal file
165
Node.m
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#import "BooleanIO.h"
|
||||
#import "IntegerIO.h"
|
||||
#import "StringIO.h"
|
||||
#import "Node.h"
|
||||
#import "InputStream.h"
|
||||
#import "Blob.h"
|
||||
#import "SetNSError.h"
|
||||
#import "Tree.h"
|
||||
|
||||
@implementation Node
|
||||
@synthesize isTree, dataSize, thumbnailSHA1, previewSHA1, xattrsSHA1, xattrsSize, aclSHA1, uid, gid, mode, mtime_sec, mtime_nsec, flags, finderFlags, extendedFinderFlags, finderFileType, finderFileCreator, isFileExtensionHidden, treeVersion, st_rdev;
|
||||
@synthesize ctime_sec, ctime_nsec, createTime_sec, createTime_nsec, st_nlink, st_ino;
|
||||
@dynamic treeSHA1, dataSHA1s;
|
||||
|
||||
- (id)initWithInputStream:(id <BufferedInputStream>)is treeVersion:(int)theTreeVersion error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
treeVersion = theTreeVersion;
|
||||
dataSHA1s = [[NSMutableArray alloc] init];
|
||||
BOOL ret = NO;
|
||||
do {
|
||||
if (![BooleanIO read:&isTree from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
int dataSHA1sCount;
|
||||
if (![IntegerIO readInt32:&dataSHA1sCount from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < dataSHA1sCount; i++) {
|
||||
NSString *dataSHA1;
|
||||
if (![StringIO read:&dataSHA1 from:is error:error]) {
|
||||
break;
|
||||
}
|
||||
[dataSHA1s addObject:dataSHA1];
|
||||
}
|
||||
ret = [IntegerIO readUInt64:&dataSize from:is error:error]
|
||||
&& [StringIO read:&thumbnailSHA1 from:is error:error]
|
||||
&& [StringIO read:&previewSHA1 from:is error:error]
|
||||
&& [StringIO read:&xattrsSHA1 from:is error:error]
|
||||
&& [IntegerIO readUInt64:&xattrsSize from:is error:error]
|
||||
&& [StringIO read:&aclSHA1 from:is error:error]
|
||||
&& [IntegerIO readInt32:&uid from:is error:error]
|
||||
&& [IntegerIO readInt32:&gid from:is error:error]
|
||||
&& [IntegerIO readInt32:&mode from:is error:error]
|
||||
&& [IntegerIO readInt64:&mtime_sec from:is error:error]
|
||||
&& [IntegerIO readInt64:&mtime_nsec from:is error:error]
|
||||
&& [IntegerIO readInt64:&flags from:is error:error]
|
||||
&& [IntegerIO readInt32:&finderFlags from:is error:error]
|
||||
&& [IntegerIO readInt32:&extendedFinderFlags from:is error:error]
|
||||
&& [StringIO read:&finderFileType from:is error:error]
|
||||
&& [StringIO read:&finderFileCreator from:is error:error]
|
||||
&& [BooleanIO read:&isFileExtensionHidden from:is error:error]
|
||||
&& [IntegerIO readInt32:&st_dev from:is error:error]
|
||||
&& [IntegerIO readInt32:&st_ino from:is error:error]
|
||||
&& [IntegerIO readUInt32:&st_nlink from:is error:error]
|
||||
&& [IntegerIO readInt32:&st_rdev from:is error:error]
|
||||
&& [IntegerIO readInt64:&ctime_sec from:is error:error]
|
||||
&& [IntegerIO readInt64:&ctime_nsec from:is error:error]
|
||||
&& [IntegerIO readInt64:&createTime_sec from:is error:error]
|
||||
&& [IntegerIO readInt64:&createTime_nsec from:is error:error]
|
||||
&& [IntegerIO readInt64:&st_blocks from:is error:error]
|
||||
&& [IntegerIO readUInt32:&st_blksize from:is error:error];
|
||||
[thumbnailSHA1 retain];
|
||||
[previewSHA1 retain];
|
||||
[xattrsSHA1 retain];
|
||||
[aclSHA1 retain];
|
||||
[finderFileType retain];
|
||||
[finderFileCreator retain];
|
||||
} while(0);
|
||||
if (!ret) {
|
||||
[self release];
|
||||
self = nil;
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[dataSHA1s release];
|
||||
[thumbnailSHA1 release];
|
||||
[previewSHA1 release];
|
||||
[xattrsSHA1 release];
|
||||
[aclSHA1 release];
|
||||
[finderFileType release];
|
||||
[finderFileCreator release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)writeToData:(NSMutableData *)data {
|
||||
[BooleanIO write:isTree to:data];
|
||||
[IntegerIO writeInt32:(int32_t)[dataSHA1s count] to:data];
|
||||
for (NSString *dataSHA1 in dataSHA1s) {
|
||||
[StringIO write:dataSHA1 to:data];
|
||||
}
|
||||
[IntegerIO writeUInt64:dataSize to:data];
|
||||
[StringIO write:thumbnailSHA1 to:data];
|
||||
[StringIO write:previewSHA1 to:data];
|
||||
[StringIO write:xattrsSHA1 to:data];
|
||||
[IntegerIO writeUInt64:xattrsSize to:data];
|
||||
[StringIO write:aclSHA1 to:data];
|
||||
[IntegerIO writeInt32:uid to:data];
|
||||
[IntegerIO writeInt32:gid to:data];
|
||||
[IntegerIO writeInt32:mode to:data];
|
||||
[IntegerIO writeInt64:mtime_sec to:data];
|
||||
[IntegerIO writeInt64:mtime_nsec to:data];
|
||||
[IntegerIO writeInt64:flags to:data];
|
||||
[IntegerIO writeInt32:finderFlags to:data];
|
||||
[IntegerIO writeInt32:extendedFinderFlags to:data];
|
||||
[StringIO write:finderFileType to:data];
|
||||
[StringIO write:finderFileCreator to:data];
|
||||
[BooleanIO write:isFileExtensionHidden to:data];
|
||||
[IntegerIO writeInt32:st_dev to:data];
|
||||
[IntegerIO writeInt32:st_ino to:data];
|
||||
[IntegerIO writeUInt32:st_nlink to:data];
|
||||
[IntegerIO writeInt32:st_rdev to:data];
|
||||
[IntegerIO writeInt64:ctime_sec to:data];
|
||||
[IntegerIO writeInt64:ctime_nsec to:data];
|
||||
[IntegerIO writeInt64:createTime_sec to:data];
|
||||
[IntegerIO writeInt64:createTime_nsec to:data];
|
||||
[IntegerIO writeInt64:st_blocks to:data];
|
||||
[IntegerIO writeUInt32:st_blksize to:data];
|
||||
}
|
||||
- (BOOL)dataMatchesStatData:(struct stat *)st {
|
||||
return (st->st_mtimespec.tv_sec == mtime_sec && st->st_mtimespec.tv_nsec == mtime_nsec & st->st_size == dataSize);
|
||||
}
|
||||
- (NSString *)treeSHA1 {
|
||||
NSAssert(isTree, @"must be a Tree");
|
||||
return [dataSHA1s objectAtIndex:0];
|
||||
}
|
||||
- (NSArray *)dataSHA1s {
|
||||
return dataSHA1s;
|
||||
}
|
||||
@end
|
||||
47
PackIndexEntry.h
Normal file
47
PackIndexEntry.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
@interface PackIndexEntry : NSObject {
|
||||
NSString *packSHA1;
|
||||
unsigned long long offset;
|
||||
unsigned long long dataLength;
|
||||
NSString *objectSHA1;
|
||||
}
|
||||
- (id)initWithPackSHA1:(NSString *)thePackSHA1 offset:(unsigned long long)theOffset dataLength:(unsigned long long)theDataLength objectSHA1:(NSString *)theObjectSHA1;
|
||||
- (NSString *)packSHA1;
|
||||
- (unsigned long long)offset;
|
||||
- (unsigned long long)dataLength;
|
||||
- (NSString *)objectSHA1;
|
||||
@end
|
||||
63
PackIndexEntry.m
Normal file
63
PackIndexEntry.m
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "PackIndexEntry.h"
|
||||
|
||||
|
||||
@implementation PackIndexEntry
|
||||
- (id)initWithPackSHA1:(NSString *)thePackSHA1 offset:(unsigned long long)theOffset dataLength:(unsigned long long)theDataLength objectSHA1:(NSString *)theObjectSHA1 {
|
||||
if (self = [super init]) {
|
||||
packSHA1 = [thePackSHA1 copy];
|
||||
offset = theOffset;
|
||||
dataLength = theDataLength;
|
||||
objectSHA1 = [theObjectSHA1 copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[packSHA1 release];
|
||||
[objectSHA1 release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSString *)packSHA1 {
|
||||
return packSHA1;
|
||||
}
|
||||
- (unsigned long long)offset {
|
||||
return offset;
|
||||
}
|
||||
- (unsigned long long)dataLength {
|
||||
return dataLength;
|
||||
}
|
||||
- (NSString *)objectSHA1 {
|
||||
return objectSHA1;
|
||||
}
|
||||
@end
|
||||
66
PackSet.h
Normal file
66
PackSet.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class Blob;
|
||||
@class S3Service;
|
||||
@class ServerBlob;
|
||||
|
||||
@interface PackSet : NSObject {
|
||||
NSString *packSetName;
|
||||
NSString *escapedPackSetName;
|
||||
NSString *packSetDir;
|
||||
S3Service *s3;
|
||||
NSString *s3BucketName;
|
||||
NSString *computerUUID;
|
||||
BOOL keepPacksLocal;
|
||||
NSMutableSet *packSHA1s;
|
||||
NSString *currentPackSHA1;
|
||||
NSMutableDictionary *packIndexEntries;
|
||||
}
|
||||
+ (NSString *)errorDomain;
|
||||
+ (unsigned long long)maxPackFileSizeMB;
|
||||
+ (unsigned long long)maxPackItemSizeBytes;
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName;
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName;
|
||||
|
||||
- (id)initWithName:(NSString *)thePackSetName
|
||||
s3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID
|
||||
keepPacksLocal:(BOOL)isKeepPacksLocal
|
||||
packSHA1s:(NSArray *)thePackSHA1s
|
||||
error:(NSError **)error;
|
||||
- (NSString *)name;
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 error:(NSError **)error;
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1;
|
||||
@end
|
||||
200
PackSet.m
Normal file
200
PackSet.m
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "PackSet.h"
|
||||
#import "S3Service.h"
|
||||
#import "SHA1Hash.h"
|
||||
#import "S3ObjectReceiver.h"
|
||||
#import "SetNSError.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "PackSetSet.h"
|
||||
#import "NSData-InputStream.h"
|
||||
#import "ServerBlob.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "DiskPackIndex.h"
|
||||
#import "PackIndexEntry.h"
|
||||
#import "DiskPack.h"
|
||||
#import "RegexKitLite.h"
|
||||
#import "HTTP.h"
|
||||
|
||||
static unsigned long long DEFAULT_MAX_PACK_FILE_SIZE_MB = 10;
|
||||
static unsigned long long DEFAULT_MAX_PACK_ITEM_SIZE_BYTES = 65536;
|
||||
static double DEFAULT_MAX_REUSABLE_PACK_FILE_SIZE_FRACTION = 0.6;
|
||||
|
||||
|
||||
|
||||
@interface PackSet (internal)
|
||||
+ (unsigned long long)maxReusablePackFileSizeBytes;
|
||||
- (BOOL)loadPackIndexEntries:(NSString *)packSHA1 totalDataSize:(unsigned long long *)totalDataSize error:(NSError **)error;
|
||||
- (PackIndexEntry *)packIndexEntryForObjectSHA1:(NSString *)objectSHA1 error:(NSError **)error;
|
||||
- (PackIndexEntry *)packIndexEntryForObjectSHA1:(NSString *)objectSHA1 inPackSHA1:(NSString *)packSHA1 error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation PackSet
|
||||
+ (NSString *)errorDomain {
|
||||
return @"PackSetErrorDomain";
|
||||
}
|
||||
+ (unsigned long long)maxPackFileSizeMB {
|
||||
return DEFAULT_MAX_PACK_FILE_SIZE_MB;
|
||||
}
|
||||
+ (unsigned long long)maxPackItemSizeBytes {
|
||||
return DEFAULT_MAX_PACK_ITEM_SIZE_BYTES;
|
||||
}
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName {
|
||||
return [NSString stringWithFormat:@"%@/%@", [PackSetSet s3PathWithS3BucketName:theS3BucketName computerUUID:theComputerUUID], [thePackSetName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)theComputerUUID packSetName:(NSString *)thePackSetName {
|
||||
return [NSString stringWithFormat:@"%@/%@", [PackSetSet localPathWithComputerUUID:theComputerUUID], [thePackSetName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
- (id)initWithName:(NSString *)thePackSetName
|
||||
s3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID
|
||||
keepPacksLocal:(BOOL)isKeepPacksLocal
|
||||
packSHA1s:(NSArray *)thePackSHA1s
|
||||
error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
packSetName = [thePackSetName copy];
|
||||
s3 = [theS3 retain];
|
||||
s3BucketName = [theS3BucketName copy];
|
||||
computerUUID = [theComputerUUID copy];
|
||||
keepPacksLocal = isKeepPacksLocal;
|
||||
escapedPackSetName = [[thePackSetName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] copy];
|
||||
packSetDir = [[PackSet localPathWithComputerUUID:theComputerUUID packSetName:packSetName] retain];
|
||||
packSHA1s = [[NSMutableSet alloc] initWithArray:thePackSHA1s];
|
||||
packIndexEntries = [[NSMutableDictionary alloc] init];
|
||||
for (NSString *packSHA1 in packSHA1s) {
|
||||
unsigned long long totalDataSize = 0;
|
||||
if (![self loadPackIndexEntries:packSHA1 totalDataSize:&totalDataSize error:error]) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
if (totalDataSize < [PackSet maxReusablePackFileSizeBytes] && currentPackSHA1 == nil) {
|
||||
currentPackSHA1 = [packSHA1 copy];
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[packSetName release];
|
||||
[escapedPackSetName release];
|
||||
[packSetDir release];
|
||||
[s3 release];
|
||||
[s3BucketName release];
|
||||
[computerUUID release];
|
||||
[packSHA1s release];
|
||||
[packIndexEntries release];
|
||||
[currentPackSHA1 release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSString *)name {
|
||||
return packSetName;
|
||||
}
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 error:(NSError **)error {
|
||||
HSLogTrace(@"packset %@ looking for SHA1 %@", packSetName, sha1);
|
||||
NSError *myError = nil;
|
||||
PackIndexEntry *entry = [self packIndexEntryForObjectSHA1:sha1 error:&myError];
|
||||
if (entry == nil && [myError code] != ERROR_NOT_FOUND) {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
HSLogError(@"error reading pack index entry for %@ from pack set %@: %@", sha1, packSetName, [myError localizedDescription]);
|
||||
return nil;
|
||||
}
|
||||
if (entry != nil) {
|
||||
NSError *myError = nil;
|
||||
DiskPack *diskPack = [[DiskPack alloc] initWithS3Service:s3 s3BucketName:s3BucketName computerUUID:computerUUID packSetName:packSetName packSHA1:[entry packSHA1]];
|
||||
if (![diskPack makeLocal:&myError]) {
|
||||
[diskPack release];
|
||||
if ([[myError domain] isEqualToString:[S3Service errorDomain]] && [myError code] == HTTP_NOT_FOUND) {
|
||||
SETNSERROR(@"PackSetErrorDomain", ERROR_NOT_FOUND, @"pack %@ not found in S3: %@", [entry packSHA1], [myError localizedDescription]);
|
||||
} else if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
ServerBlob *sb = [diskPack newServerBlobForObjectAtOffset:[entry offset] error:error];
|
||||
[diskPack release];
|
||||
return sb;
|
||||
}
|
||||
SETNSERROR(@"PackErrorDomain", ERROR_NOT_FOUND, @"sha1 %@ not found", sha1);
|
||||
return nil;
|
||||
}
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1 {
|
||||
return [packIndexEntries objectForKey:sha1] != nil;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation PackSet (internal)
|
||||
+ (unsigned long long)maxReusablePackFileSizeBytes {
|
||||
return (unsigned long long)((double)([PackSet maxPackFileSizeMB] * 1000000) * DEFAULT_MAX_REUSABLE_PACK_FILE_SIZE_FRACTION);
|
||||
}
|
||||
- (PackIndexEntry *)packIndexEntryForObjectSHA1:(NSString *)objectSHA1 error:(NSError **)error {
|
||||
PackIndexEntry *pie = [packIndexEntries objectForKey:objectSHA1];
|
||||
if (pie == nil) {
|
||||
SETNSERROR(@"PackErrorDomain", ERROR_NOT_FOUND, @"pie not found for %@", objectSHA1);
|
||||
}
|
||||
return pie;
|
||||
}
|
||||
- (PackIndexEntry *)packIndexEntryForObjectSHA1:(NSString *)objectSHA1 inPackSHA1:(NSString *)packSHA1 error:(NSError **)error {
|
||||
PackIndexEntry *pie = [packIndexEntries objectForKey:objectSHA1];
|
||||
if (pie == nil) {
|
||||
SETNSERROR(@"PackErrorDomain", ERROR_NOT_FOUND, @"pie not found for %@", objectSHA1);
|
||||
}
|
||||
return pie;
|
||||
}
|
||||
- (BOOL)loadPackIndexEntries:(NSString *)packSHA1 totalDataSize:(unsigned long long *)totalDataSize error:(NSError **)error {
|
||||
*totalDataSize = 0;
|
||||
DiskPackIndex *index = [[DiskPackIndex alloc] initWithS3Service:s3 s3BucketName:s3BucketName computerUUID:computerUUID packSetName:packSetName packSHA1:packSHA1];
|
||||
BOOL ret = NO;
|
||||
do {
|
||||
if (![index makeLocal:error]) {
|
||||
break;
|
||||
}
|
||||
NSArray *pies = [index allPackIndexEntries:error];
|
||||
if (pies == nil) {
|
||||
break;
|
||||
}
|
||||
for (PackIndexEntry *pie in pies) {
|
||||
[packIndexEntries setObject:pie forKey:[pie objectSHA1]];
|
||||
unsigned long long dataEndOffset = [pie offset] + [pie dataLength];
|
||||
if (dataEndOffset > *totalDataSize) {
|
||||
*totalDataSize = dataEndOffset;
|
||||
}
|
||||
}
|
||||
ret = YES;
|
||||
} while (0);
|
||||
[index release];
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
54
PackSetSet.h
Normal file
54
PackSetSet.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class ServerBlob;
|
||||
@class S3Service;
|
||||
@class Blob;
|
||||
|
||||
@interface PackSetSet : NSObject {
|
||||
S3Service *s3;
|
||||
NSString *s3BucketName;
|
||||
NSString *computerUUID;
|
||||
NSMutableDictionary *packSets;
|
||||
}
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID;
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)computerUUID;
|
||||
- (id)initWithS3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID;
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName error:(NSError **)error;
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName;
|
||||
|
||||
// Sync local cache files to S3 data; reload PackIndexEntries from local cache files.
|
||||
- (BOOL)resetFromS3:(NSError **)error;
|
||||
@end
|
||||
224
PackSetSet.m
Normal file
224
PackSetSet.m
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "PackSetSet.h"
|
||||
#import "PackSet.h"
|
||||
#import "SetNSError.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "S3Service.h"
|
||||
#import "ArqUserLibrary.h"
|
||||
#import "RegexKitLite.h"
|
||||
|
||||
@interface PackSetSet (internal)
|
||||
- (NSDictionary *)packSHA1sByPackSetNameFromS3:(NSError **)error;
|
||||
- (NSMutableSet *)diskPackSetNames:(NSError **)error;
|
||||
- (PackSet *)packSetForName:(NSString *)packSetName error:(NSError **)error;
|
||||
- (NSArray *)cachedPackSHA1sForPackSet:(NSString *)packSetName error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation PackSetSet
|
||||
+ (NSString *)s3PathWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID {
|
||||
return [NSString stringWithFormat:@"/%@/%@/packsets", theS3BucketName, theComputerUUID];
|
||||
}
|
||||
+ (NSString *)localPathWithComputerUUID:(NSString *)computerUUID {
|
||||
return [NSString stringWithFormat:@"%@/%@/packsets", [ArqUserLibrary arqCachesPath], computerUUID];
|
||||
}
|
||||
|
||||
- (id)initWithS3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID {
|
||||
if (self = [super init]) {
|
||||
s3 = [theS3 retain];
|
||||
s3BucketName = [theS3BucketName copy];
|
||||
computerUUID = [theComputerUUID copy];
|
||||
packSets = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[s3 release];
|
||||
[s3BucketName release];
|
||||
[computerUUID release];
|
||||
[packSets release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName error:(NSError **)error {
|
||||
PackSet *packSet = [self packSetForName:packSetName error:error];
|
||||
if (packSet == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [packSet newServerBlobForSHA1:sha1 error:error];
|
||||
}
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName {
|
||||
BOOL contains = [[packSets objectForKey:packSetName] containsBlobForSHA1:sha1];
|
||||
return contains;
|
||||
}
|
||||
- (BOOL)resetFromS3:(NSError **)error {
|
||||
HSLogDebug(@"resetting pack sets from S3");
|
||||
[packSets removeAllObjects];
|
||||
NSDictionary *s3PackSHA1sByPackSetName = [self packSHA1sByPackSetNameFromS3:error];
|
||||
if (s3PackSHA1sByPackSetName == nil) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove disk pack sets that don't exist in S3.
|
||||
//
|
||||
NSMutableSet *diskPackSetNames = [self diskPackSetNames:error];
|
||||
if (diskPackSetNames == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSMutableSet *s3PackSetNames = [NSMutableSet setWithArray:[s3PackSHA1sByPackSetName allKeys]];
|
||||
[diskPackSetNames minusSet:s3PackSetNames];
|
||||
for (NSString *bogusDiskPackSetName in diskPackSetNames) {
|
||||
NSString *packSetPath = [PackSet localPathWithComputerUUID:computerUUID packSetName:bogusDiskPackSetName];
|
||||
HSLogDebug(@"removing local pack set that doesn't exist in S3: %@", packSetPath);
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:packSetPath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create PackSets, make index files local, and load PackIndexEntries into memory.
|
||||
//
|
||||
for (NSString *s3PackSetName in [s3PackSHA1sByPackSetName allKeys]) {
|
||||
NSArray *packSHA1s = [s3PackSHA1sByPackSetName objectForKey:s3PackSetName];
|
||||
PackSet *packSet = [[[PackSet alloc] initWithName:s3PackSetName
|
||||
s3Service:s3
|
||||
s3BucketName:s3BucketName
|
||||
computerUUID:computerUUID
|
||||
keepPacksLocal:[s3PackSetName hasSuffix:@"-trees"]
|
||||
packSHA1s:packSHA1s error:error] autorelease];
|
||||
if (packSet == nil) {
|
||||
return NO;
|
||||
}
|
||||
[packSets setObject:packSet forKey:s3PackSetName];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
@implementation PackSetSet (internal)
|
||||
- (NSDictionary *)packSHA1sByPackSetNameFromS3:(NSError **)error {
|
||||
NSMutableDictionary *packSHA1sByPackSetName = [NSMutableDictionary dictionary];
|
||||
NSString *packSetPrefix = [PackSet s3PathWithS3BucketName:s3BucketName computerUUID:computerUUID packSetName:@""];
|
||||
NSArray *s3Paths = [s3 pathsWithPrefix:packSetPrefix error:error];
|
||||
if (s3Paths == nil) {
|
||||
return nil;
|
||||
}
|
||||
// Format: /<s3bucketname>/<computeruuid>/packsets/<packsetname>/<sha1>.pack
|
||||
NSString *pattern = [NSString stringWithFormat:@"^%@([^/]+)/(.+)\\.pack$", packSetPrefix];
|
||||
for (NSString *s3Path in s3Paths) {
|
||||
NSRange packSetNameRange = [s3Path rangeOfRegex:pattern capture:1];
|
||||
NSRange sha1Range = [s3Path rangeOfRegex:pattern capture:2];
|
||||
if (packSetNameRange.location != NSNotFound && sha1Range.location != NSNotFound) {
|
||||
NSString *escapedPackSetName = [s3Path substringWithRange:packSetNameRange];
|
||||
NSString *packSetName = [escapedPackSetName stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *packSHA1 = [s3Path substringWithRange:sha1Range];
|
||||
NSMutableArray *packSHA1s = [packSHA1sByPackSetName objectForKey:packSetName];
|
||||
if (packSHA1s == nil) {
|
||||
packSHA1s = [NSMutableArray array];
|
||||
[packSHA1sByPackSetName setObject:packSHA1s forKey:packSetName];
|
||||
}
|
||||
[packSHA1s addObject:packSHA1];
|
||||
}
|
||||
}
|
||||
return packSHA1sByPackSetName;
|
||||
}
|
||||
- (NSMutableSet *)diskPackSetNames:(NSError **)error {
|
||||
NSMutableSet *diskPackSetNames = [NSMutableSet set];
|
||||
NSString *packSetsDir = [PackSetSet localPathWithComputerUUID:computerUUID];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:packSetsDir]) {
|
||||
NSArray *packSetNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:packSetsDir error:error];
|
||||
if (packSetNames == nil) {
|
||||
return nil;
|
||||
}
|
||||
for (NSString *packSetName in packSetNames) {
|
||||
if (![packSetName hasPrefix:@"."]) {
|
||||
[diskPackSetNames addObject:packSetName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return diskPackSetNames;
|
||||
}
|
||||
- (PackSet *)packSetForName:(NSString *)packSetName error:(NSError **)error {
|
||||
PackSet *packSet = [packSets objectForKey:packSetName];
|
||||
if (packSet == nil) {
|
||||
NSError *myError;
|
||||
NSArray *packSHA1s = [self cachedPackSHA1sForPackSet:packSetName error:&myError];
|
||||
if (packSHA1s == nil) {
|
||||
HSLogError(@"error reading cached pack sets: %@", [myError localizedDescription]);
|
||||
packSHA1s = [NSArray array];
|
||||
}
|
||||
packSet = [[PackSet alloc] initWithName:packSetName
|
||||
s3Service:s3
|
||||
s3BucketName:s3BucketName
|
||||
computerUUID:computerUUID
|
||||
keepPacksLocal:[packSetName hasSuffix:@"-trees"]
|
||||
packSHA1s:packSHA1s
|
||||
error:error];
|
||||
if (packSet == nil) {
|
||||
return nil;
|
||||
}
|
||||
[packSets setObject:packSet forKey:packSetName];
|
||||
[packSet release];
|
||||
}
|
||||
return packSet;
|
||||
}
|
||||
- (NSArray *)cachedPackSHA1sForPackSet:(NSString *)packSetName error:(NSError **)error {
|
||||
NSString *packSetDir = [PackSet localPathWithComputerUUID:computerUUID packSetName:packSetName];
|
||||
NSMutableArray *ret = [NSMutableArray array];
|
||||
BOOL isDir = NO;
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:packSetDir isDirectory:&isDir] && isDir) {
|
||||
NSArray *dirNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:packSetDir error:error];
|
||||
if (dirNames == nil) {
|
||||
return nil;
|
||||
}
|
||||
for (NSString *dirName in dirNames) {
|
||||
NSString *dir = [packSetDir stringByAppendingPathComponent:dirName];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:dir isDirectory:&isDir] && isDir) {
|
||||
NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:error];
|
||||
if (fileNames == nil) {
|
||||
return nil;
|
||||
}
|
||||
for (NSString *fileName in fileNames) {
|
||||
NSRange sha1Range = [fileName rangeOfRegex:@"^(.+)\\.index$" capture:1];
|
||||
if (sha1Range.location != NSNotFound) {
|
||||
NSString *sha1 = [dirName stringByAppendingString:[fileName substringWithRange:sha1Range]];
|
||||
[ret addObject:sha1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
48
RestoreNode.h
Normal file
48
RestoreNode.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "InputStream.h"
|
||||
#import "OutputStream.h"
|
||||
@class Tree;
|
||||
@class Node;
|
||||
|
||||
@interface RestoreNode : NSObject {
|
||||
Tree *tree;
|
||||
NSString *nodeName;
|
||||
NSString *relativePath;
|
||||
}
|
||||
- (id)initWithTree:(Tree *)theTree nodeName:(NSString *)theNodeName relativePath:(NSString *)theRelativePath;
|
||||
- (Tree *)tree;
|
||||
- (Node *)node;
|
||||
- (NSString *)relativePath;
|
||||
@end
|
||||
63
RestoreNode.m
Normal file
63
RestoreNode.m
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "RestoreNode.h"
|
||||
#import "Tree.h"
|
||||
#import "Node.h"
|
||||
#import "StringIO.h"
|
||||
|
||||
@implementation RestoreNode
|
||||
- (id)initWithTree:(Tree *)theTree nodeName:(NSString *)theNodeName relativePath:(NSString *)theRelativePath {
|
||||
if (self = [super init]) {
|
||||
tree = [theTree retain];
|
||||
nodeName = [theNodeName copy];
|
||||
NSAssert((nodeName == nil) || ([tree childNodeWithName:nodeName] != nil), @"node doesn't exist in Tree!");
|
||||
relativePath = [theRelativePath copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[tree release];
|
||||
[nodeName release];
|
||||
[relativePath release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (Tree *)tree {
|
||||
return tree;
|
||||
}
|
||||
- (Node *)node {
|
||||
return [tree childNodeWithName:nodeName];
|
||||
}
|
||||
- (NSString *)relativePath {
|
||||
return relativePath;
|
||||
}
|
||||
@end
|
||||
48
Restorer.h
Normal file
48
Restorer.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class S3Service;
|
||||
@class S3Fark;
|
||||
@class S3Repo;
|
||||
|
||||
@interface Restorer : NSObject {
|
||||
S3Fark *fark;
|
||||
S3Repo *repo;
|
||||
NSString *bucketName;
|
||||
NSString *rootPath;
|
||||
NSMutableArray *restoreNodes;
|
||||
NSMutableDictionary *hardlinks;
|
||||
}
|
||||
- (id)initWithS3Service:(S3Service *)theS3 s3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID bucketUUID:(NSString *)theBucketUUID bucketName:(NSString *)theBucketName encryptionKey:(NSString *)theEncryptionKey;
|
||||
- (BOOL)restore:(NSError **)error;
|
||||
@end
|
||||
467
Restorer.m
Normal file
467
Restorer.m
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#import "Restorer.h"
|
||||
#import "S3Fark.h"
|
||||
#import "S3Repo.h"
|
||||
#import "SetNSError.h"
|
||||
#import "Tree.h"
|
||||
#import "Node.h"
|
||||
#import "RestoreNode.h"
|
||||
#import "FileAttributes.h"
|
||||
#import "NSData-InputStream.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "XAttrSet.h"
|
||||
#import "FileOutputStream.h"
|
||||
#import "NSFileManager_extra.h"
|
||||
#import "CFStreamPair.h"
|
||||
#import "NSErrorCodes.h"
|
||||
|
||||
@interface Restorer (internal)
|
||||
- (BOOL)addRestoreNodesForTreeSHA1:(NSString *)treeSHA1 relativePath:(NSString *)relativePath error:(NSError **)error;
|
||||
- (BOOL)restoreRestoreNode:(RestoreNode *)rn error:(NSError **)error;
|
||||
- (BOOL)createFile:(Node *)node atPath:(NSString *)path error:(NSError **)error;
|
||||
- (BOOL)createFileAtPath:(NSString *)path fromSHA1s:(NSArray *)dataSHA1s error:(NSError **)error;
|
||||
- (BOOL)createFileOnceAtPath:(NSString *)path fromSHA1s:(NSArray *)dataSHA1s error:(NSError **)error;
|
||||
- (BOOL)appendBlobForSHA1:(NSString *)sha1 toFile:(FileOutputStream *)fos error:(NSError **)error;
|
||||
- (BOOL)applyTree:(Tree *)tree toPath:(NSString *)restorePath error:(NSError **)error;
|
||||
- (BOOL)applyNode:(Node *)node toPath:(NSString *)restorePath error:(NSError **)error;
|
||||
- (BOOL)applyACLSHA1:(NSString *)aclSHA1 toFileAttributes:(FileAttributes *)fa error:(NSError **)error;
|
||||
- (BOOL)applyXAttrsSHA1:(NSString *)xattrsSHA1 toFile:(NSString *)path error:(NSError **)error;
|
||||
- (BOOL)createSymLink:(Node *)node path:(NSString *)symLinkFile target:(NSString *)target error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation Restorer
|
||||
- (id)initWithS3Service:(S3Service *)theS3 s3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID bucketUUID:(NSString *)theBucketUUID bucketName:(NSString *)theBucketName encryptionKey:(NSString *)theEncryptionKey {
|
||||
if (self = [super init]) {
|
||||
fark = [[S3Fark alloc] initWithS3Service:theS3 s3BucketName:theS3BucketName computerUUID:theComputerUUID];
|
||||
repo = [[S3Repo alloc] initWithS3Service:theS3 s3BucketName:theS3BucketName computerUUID:theComputerUUID bucketUUID:theBucketUUID encrypted:YES encryptionKey:theEncryptionKey fark:fark ensureCacheIntegrity:NO];
|
||||
bucketName = [theBucketName copy];
|
||||
rootPath = [[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:theBucketName] copy];
|
||||
restoreNodes = [[NSMutableArray alloc] init];
|
||||
hardlinks = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[fark release];
|
||||
[repo release];
|
||||
[bucketName release];
|
||||
[rootPath release];
|
||||
[restoreNodes release];
|
||||
[hardlinks release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)restore:(NSError **)error {
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:rootPath]) {
|
||||
SETNSERROR(@"RestorerErrorDomain", -1, @"%@ already exists", rootPath);
|
||||
return NO;
|
||||
}
|
||||
if (![fark reloadPacksFromS3:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (![[NSFileManager defaultManager] createDirectoryAtPath:rootPath withIntermediateDirectories:YES attributes:nil error:error]) {
|
||||
HSLogError(@"failed to create directory %@", rootPath);
|
||||
return NO;
|
||||
}
|
||||
NSString *headSHA1 = nil;
|
||||
if (![repo localHeadSHA1:&headSHA1 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (headSHA1 == nil) {
|
||||
SETNSERROR(@"RestorerErrorDomain", -1, @"no backup found");
|
||||
return NO;
|
||||
}
|
||||
Commit *head = nil;
|
||||
if (![repo commit:&head forSHA1:headSHA1 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (![self addRestoreNodesForTreeSHA1:[head treeSHA1] relativePath:@"" error:error]) {
|
||||
return NO;
|
||||
}
|
||||
for (RestoreNode *rn in restoreNodes) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSError *myError = nil;
|
||||
BOOL ret = [self restoreRestoreNode:rn error:&myError];
|
||||
[myError retain];
|
||||
[pool drain];
|
||||
[myError autorelease];
|
||||
if (!ret) {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation Restorer (internal)
|
||||
- (BOOL)addRestoreNodesForTreeSHA1:(NSString *)treeSHA1 relativePath:(NSString *)relativePath error:(NSError **)error {
|
||||
Tree *tree = nil;
|
||||
if (![repo tree:&tree forSHA1:treeSHA1 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
RestoreNode *treeRN = [[RestoreNode alloc] initWithTree:tree nodeName:nil relativePath:relativePath];
|
||||
[restoreNodes addObject:treeRN];
|
||||
[treeRN release];
|
||||
for (NSString *childNodeName in [tree childNodeNames]) {
|
||||
Node *childNode = [tree childNodeWithName:childNodeName];
|
||||
NSString *childRelativePath = [NSString stringWithFormat:@"%@/%@", relativePath, childNodeName];
|
||||
if ([childNode isTree]) {
|
||||
if (![self addRestoreNodesForTreeSHA1:[childNode treeSHA1] relativePath:childRelativePath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
RestoreNode *childRN = [[RestoreNode alloc] initWithTree:tree nodeName:childNodeName relativePath:childRelativePath];
|
||||
[restoreNodes addObject:childRN];
|
||||
[childRN release];
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)restoreRestoreNode:(RestoreNode *)rn error:(NSError **)error {
|
||||
printf("restoring %s%s\n", [bucketName UTF8String], [[rn relativePath] UTF8String]);
|
||||
NSString *restorePath = [rootPath stringByAppendingPathComponent:[rn relativePath]];
|
||||
NSString *parentPath = [restorePath stringByDeletingLastPathComponent];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:parentPath]
|
||||
&& ![[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:error]) {
|
||||
HSLogError(@"failed to create directory %@", parentPath);
|
||||
return NO;
|
||||
}
|
||||
BOOL createdFile = NO;
|
||||
int nlink = [rn node] == nil ? [[rn tree] st_nlink] : [[rn node] st_nlink];
|
||||
if (nlink > 1) {
|
||||
int ino = [rn node] == nil ? [[rn tree] st_ino] : [[rn node] st_ino];
|
||||
NSNumber *inode = [NSNumber numberWithInt:ino];
|
||||
RestoreNode *existing = [hardlinks objectForKey:inode];
|
||||
if (existing != nil) {
|
||||
// Link.
|
||||
NSString *existingPath = [rootPath stringByAppendingPathComponent:[existing relativePath]];
|
||||
if (([existing node] == nil) != ([rn node] == nil)) {
|
||||
SETNSERROR(@"RestoreErrorDomain", -1, @"cannot link a directory to a file");
|
||||
HSLogError(@"can't link directory to a file");
|
||||
return NO;
|
||||
}
|
||||
if (link([existingPath fileSystemRepresentation], [restorePath fileSystemRepresentation]) == -1) {
|
||||
SETNSERROR(@"RestoreErrorDomain", -1, @"link(%@,%@): %s", existingPath, restorePath, strerror(errno));
|
||||
HSLogError(@"link() failed");
|
||||
return NO;
|
||||
}
|
||||
createdFile = YES;
|
||||
} else {
|
||||
[hardlinks setObject:rn forKey:inode];
|
||||
}
|
||||
}
|
||||
if (!createdFile) {
|
||||
Node *node = [rn node];
|
||||
if (node == nil) {
|
||||
Tree *tree = [rn tree];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:restorePath] && ![[NSFileManager defaultManager] createDirectoryAtPath:restorePath withIntermediateDirectories:NO attributes:nil error:error]) {
|
||||
HSLogError(@"error creating %@", restorePath);
|
||||
return NO;
|
||||
}
|
||||
if (![self applyTree:tree toPath:restorePath error:error]) {
|
||||
HSLogError(@"applyTree error");
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
int mode = [node mode];
|
||||
BOOL isFifo = (mode & S_IFIFO) == S_IFIFO;
|
||||
if (isFifo) {
|
||||
if (mkfifo([restorePath fileSystemRepresentation], mode) == -1) {
|
||||
SETNSERROR(@"RestoreErrorDomain", errno, @"mkfifo(%@): %s", restorePath, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
if (![self applyNode:node toPath:restorePath error:error]) {
|
||||
HSLogError(@"applyNode error");
|
||||
return NO;
|
||||
}
|
||||
} else if ((mode & S_IFSOCK) == S_IFSOCK) {
|
||||
// Skip socket -- restoring it doesn't make any sense.
|
||||
} else if ((mode & S_IFREG) == 0 && ((mode & S_IFCHR) == S_IFCHR || (mode & S_IFBLK) == S_IFBLK)) {
|
||||
if (![[NSFileManager defaultManager] ensureParentPathExistsForPath:restorePath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (mknod([restorePath fileSystemRepresentation], mode, [node st_rdev]) == -1) {
|
||||
SETNSERROR(@"RestorerErrorDomain", -1, @"mknod(%@): %s", restorePath, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
if (![self createFile:node atPath:restorePath error:error]) {
|
||||
HSLogError(@"createFile error");
|
||||
return NO;
|
||||
}
|
||||
if (![self applyNode:node toPath:restorePath error:error]) {
|
||||
HSLogError(@"applyNode error");
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
FileAttributes *fa = [[[FileAttributes alloc] initWithPath:restorePath error:error] autorelease];
|
||||
if (fa == nil) {
|
||||
return NO;
|
||||
}
|
||||
int flags = [fa flags];
|
||||
if (flags) {
|
||||
// Clear the flags temporarily so we can change ownership of the file.
|
||||
if (![fa applyFlags:0 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
int uid = [rn node] == nil ? [[rn tree] uid] : [[rn node] uid];
|
||||
int gid = [rn node] == nil ? [[rn tree] gid] : [[rn node] gid];
|
||||
NSError *chownError;
|
||||
if (![fa applyUID:uid gid:gid error:&chownError]) {
|
||||
fprintf(stderr, "error applying UID and GID to %s: %s\n", [restorePath fileSystemRepresentation], [[chownError localizedDescription] UTF8String]);
|
||||
}
|
||||
if (flags) {
|
||||
if (![fa applyFlags:flags error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyTree:(Tree *)tree toPath:(NSString *)path error:(NSError **)error {
|
||||
FileAttributes *fa = [[[FileAttributes alloc] initWithPath:path error:error] autorelease];
|
||||
if (!fa) {
|
||||
return NO;
|
||||
}
|
||||
if (![fa applyFinderFlags:[tree finderFlags] error:error]
|
||||
|| ![fa applyExtendedFinderFlags:[tree extendedFinderFlags] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (![self applyACLSHA1:[tree aclSHA1] toFileAttributes:fa error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (![self applyXAttrsSHA1:[tree xattrsSHA1] toFile:path error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (([tree mode] & (S_ISUID|S_ISGID|S_ISVTX) != 0) && ![fa applyMode:[tree mode] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (([tree mode] & S_IFLNK) != S_IFLNK && [tree treeVersion] >= 7 && ![fa applyMTimeSec:tree.mtime_sec mTimeNSec:tree.mtime_nsec error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (([tree treeVersion] >= 7) && ![fa applyCreateTimeSec:tree.createTime_sec createTimeNSec:tree.createTime_nsec error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (![fa applyFlags:[tree flags] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyNode:(Node *)node toPath:(NSString *)path error:(NSError **)error {
|
||||
FileAttributes *fa = [[[FileAttributes alloc] initWithPath:path error:error] autorelease];
|
||||
if (!fa) {
|
||||
return NO;
|
||||
}
|
||||
if (![self applyACLSHA1:[node aclSHA1] toFileAttributes:fa error:error]) {
|
||||
return NO;
|
||||
}
|
||||
BOOL isFifo = ([node mode] & S_IFIFO) == S_IFIFO;
|
||||
if (!isFifo) {
|
||||
if (![fa applyFinderFlags:[node finderFlags] error:error]
|
||||
|| ![fa applyExtendedFinderFlags:[node extendedFinderFlags] error:error]
|
||||
|| ![self applyXAttrsSHA1:[node xattrsSHA1] toFile:path error:error]
|
||||
|| ![fa applyFinderFileType:[node finderFileType] finderFileCreator:[node finderFileCreator] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
if (([node mode] & (S_ISUID|S_ISGID|S_ISVTX) != 0) && ![fa applyMode:[node mode] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (([node mode] & S_IFLNK) != S_IFLNK && [node treeVersion] >= 7 && ![fa applyMTimeSec:node.mtime_sec mTimeNSec:node.mtime_nsec error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (([node treeVersion] >= 7) && ![fa applyCreateTimeSec:node.createTime_sec createTimeNSec:node.createTime_nsec error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (!isFifo) {
|
||||
if (![fa applyFlags:[node flags] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)createFile:(Node *)node atPath:(NSString *)path error:(NSError **)error {
|
||||
if (![[NSFileManager defaultManager] ensureParentPathExistsForPath:path error:error]) {
|
||||
HSLogError(@"error ensuring path %@ exists", path);
|
||||
return NO;
|
||||
}
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:path error:error]) {
|
||||
HSLogError(@"error removing existing file %@", path);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
HSLogTrace(@"%qu bytes -> %@", [node dataSize], path);
|
||||
if (([node mode] & S_IFLNK) == S_IFLNK) {
|
||||
NSData *data = [repo dataForSHA1s:[node dataSHA1s] error:error];
|
||||
if (data == nil) {
|
||||
HSLogError(@"error getting data for %@", [node dataSHA1s]);
|
||||
return NO;
|
||||
}
|
||||
NSString *target = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
|
||||
if (![self createSymLink:node path:path target:target error:error]) {
|
||||
HSLogError(@"error creating sym link %@", path);
|
||||
return NO;
|
||||
}
|
||||
} else if ([node dataSize] > 0) {
|
||||
if (![self createFileAtPath:path fromSHA1s:[node dataSHA1s] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
// It's a zero-byte file.
|
||||
int fd = open([path fileSystemRepresentation], O_CREAT|O_EXCL, [node mode]);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s: %@", strerror(errno), path);
|
||||
HSLogError(@"error opening %@", path);
|
||||
return NO;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)createFileAtPath:(NSString *)path fromSHA1s:(NSArray *)dataSHA1s error:(NSError **)error {
|
||||
BOOL ret = YES;
|
||||
for (;;) {
|
||||
NSError *myError = nil;
|
||||
if (![self createFileOnceAtPath:path fromSHA1s:dataSHA1s error:&myError]) {
|
||||
if ([[myError domain] isEqualToString:[CFStreamPair errorDomain]]) {
|
||||
HSLogDebug(@"network error restoring %@ (retrying): %@", path, [myError localizedDescription]);
|
||||
} else {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
ret = NO;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)createFileOnceAtPath:(NSString *)path fromSHA1s:(NSArray *)dataSHA1s error:(NSError **)error {
|
||||
FileOutputStream *fos = [[FileOutputStream alloc] initWithPath:path append:NO];
|
||||
BOOL ret = YES;
|
||||
for (NSString *sha1 in dataSHA1s) {
|
||||
if (![self appendBlobForSHA1:sha1 toFile:fos error:error]) {
|
||||
ret = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
[fos release];
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)appendBlobForSHA1:(NSString *)sha1 toFile:(FileOutputStream *)fos error:(NSError **)error {
|
||||
ServerBlob *dataBlob = [repo newServerBlobForSHA1:sha1 error:error];
|
||||
if (dataBlob == nil) {
|
||||
HSLogError(@"error getting server blob for %@", sha1);
|
||||
return NO;
|
||||
}
|
||||
id <InputStream> is = [dataBlob newInputStream];
|
||||
[dataBlob release];
|
||||
BOOL ret = YES;
|
||||
for (;;) {
|
||||
NSUInteger received = 0;
|
||||
NSError *myError = nil;
|
||||
unsigned char *buf = [is read:&received error:&myError];
|
||||
if (buf == nil) {
|
||||
if ([myError code] != ERROR_EOF) {
|
||||
ret = NO;
|
||||
HSLogError(@"error reading from stream for blob %@: %@", sha1, [myError localizedDescription]);
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (![fos write:buf length:received error:error]) {
|
||||
ret = NO;
|
||||
break;
|
||||
}
|
||||
[NSThread sleepForTimeInterval:0.01];
|
||||
}
|
||||
[is release];
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)createSymLink:(Node *)node path:(NSString *)symLinkFile target:(NSString *)target error:(NSError **)error {
|
||||
struct stat st;
|
||||
if (lstat([symLinkFile fileSystemRepresentation], &st) == 0) {
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:symLinkFile error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
if (symlink([target fileSystemRepresentation], [symLinkFile fileSystemRepresentation]) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"symlink(%@): %s", symLinkFile, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyACLSHA1:(NSString *)aclSHA1 toFileAttributes:(FileAttributes *)fa error:(NSError **)error {
|
||||
if (aclSHA1 != nil) {
|
||||
NSData *data = [repo dataForSHA1:aclSHA1 error:error];
|
||||
if (data == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSString *aclString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
|
||||
if (![fa applyAcl:aclString error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)applyXAttrsSHA1:(NSString *)xattrsSHA1 toFile:(NSString *)path error:(NSError **)error {
|
||||
if (xattrsSHA1 != nil) {
|
||||
NSData *xattrsData = [repo dataForSHA1:xattrsSHA1 error:error];
|
||||
if (xattrsData == nil) {
|
||||
return NO;
|
||||
}
|
||||
DataInputStream *is = [xattrsData newInputStream];
|
||||
XAttrSet *set = [[[XAttrSet alloc] initWithBufferedInputStream:is error:error] autorelease];
|
||||
[is release];
|
||||
if (!set) {
|
||||
return NO;
|
||||
}
|
||||
if (![set applyToFile:path error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
53
S3Fark.h
Normal file
53
S3Fark.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class S3Service;
|
||||
@class Blob;
|
||||
@class ServerBlob;
|
||||
@class PackSetSet;
|
||||
|
||||
@interface S3Fark : NSObject {
|
||||
S3Service *s3;
|
||||
NSString *s3BucketName;
|
||||
NSString *computerUUID;
|
||||
NSThread *creatorThread;
|
||||
PackSetSet *packSetSet;
|
||||
}
|
||||
- (id)initWithS3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID;
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly error:(NSError **)error;
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly error:(NSError **)error;
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly;
|
||||
- (BOOL)reloadPacksFromS3:(NSError **)error;
|
||||
@end
|
||||
109
S3Fark.m
Normal file
109
S3Fark.m
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "S3Service.h"
|
||||
#import "S3Fark.h"
|
||||
#import "SetNSError.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "PackSetSet.h"
|
||||
#import "ServerBlob.h"
|
||||
|
||||
@interface S3Fark (internal)
|
||||
- (NSString *)pathForSHA1:(NSString *)sha1;
|
||||
@end
|
||||
|
||||
@implementation S3Fark
|
||||
- (id)initWithS3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID {
|
||||
if (self = [super init]) {
|
||||
s3 = [theS3 retain];
|
||||
s3BucketName = [theS3BucketName copy];
|
||||
computerUUID = [theComputerUUID copy];
|
||||
creatorThread = [[NSThread currentThread] retain];
|
||||
packSetSet = [[PackSetSet alloc] initWithS3Service:s3 s3BucketName:s3BucketName computerUUID:computerUUID];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[s3 release];
|
||||
[s3BucketName release];
|
||||
[computerUUID release];
|
||||
[creatorThread release];
|
||||
[packSetSet release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly error:(NSError **)error {
|
||||
ServerBlob *sb = [self newServerBlobForSHA1:sha1 packSetName:packSetName searchPackOnly:searchPackOnly error:error];
|
||||
if (sb == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSData *data = [sb slurp:error];
|
||||
[sb release];
|
||||
return data;
|
||||
}
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly error:(NSError **)error {
|
||||
NSAssert([NSThread currentThread] == creatorThread, @"must be on same thread!");
|
||||
NSError *myError = nil;
|
||||
ServerBlob *sb = [packSetSet newServerBlobForSHA1:sha1 packSetName:packSetName error:&myError];
|
||||
if (sb == nil) {
|
||||
if ([myError code] != ERROR_NOT_FOUND) {
|
||||
HSLogError(@"error reading sha1 %@ from packSetSet: %@", sha1, [myError localizedDescription]);
|
||||
}
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
if (!searchPackOnly) {
|
||||
sb = [s3 newServerBlobAtPath:[self pathForSHA1:sha1] error:error];
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly {
|
||||
NSAssert([NSThread currentThread] == creatorThread, @"must be on same thread!");
|
||||
BOOL contains = [packSetSet containsBlobForSHA1:sha1 packSetName:packSetName];
|
||||
if (!contains && !searchPackOnly) {
|
||||
contains = [s3 containsBlobAtPath:[self pathForSHA1:sha1]];
|
||||
}
|
||||
return contains;
|
||||
}
|
||||
- (BOOL)reloadPacksFromS3:(NSError **)error {
|
||||
NSAssert([NSThread currentThread] == creatorThread, @"must be on same thread!");
|
||||
return [packSetSet resetFromS3:error];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation S3Fark (internal)
|
||||
- (NSString *)pathForSHA1:(NSString *)sha1 {
|
||||
return [NSString stringWithFormat:@"/%@/%@/objects/%@", s3BucketName, computerUUID, sha1];
|
||||
}
|
||||
@end
|
||||
83
S3Repo.h
Normal file
83
S3Repo.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class S3Service;
|
||||
@class S3Fark;
|
||||
@class Commit;
|
||||
@class Tree;
|
||||
@class Blob;
|
||||
@class ServerBlob;
|
||||
|
||||
|
||||
@interface S3Repo : NSObject {
|
||||
S3Service *s3;
|
||||
NSString *s3BucketName;
|
||||
NSString *computerUUID;
|
||||
NSString *bucketUUID;
|
||||
S3Fark *fark;
|
||||
BOOL encrypted;
|
||||
NSString *encryptionKey;
|
||||
BOOL ensureCacheIntegrity;
|
||||
NSString *treesPackSetName;
|
||||
NSString *blobsPackSetName;
|
||||
}
|
||||
+ (NSString *)errorDomain;
|
||||
|
||||
- (id)initWithS3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID
|
||||
bucketUUID:(NSString *)theBucketUUID
|
||||
encrypted:(BOOL)isEncrypted
|
||||
encryptionKey:(NSString *)theEncryptionKey
|
||||
fark:(S3Fark *)theFark
|
||||
ensureCacheIntegrity:(BOOL)ensure;
|
||||
|
||||
- (BOOL)localHeadSHA1:(NSString **)localHeadSHA1 error:(NSError **)error;
|
||||
|
||||
// Returns NO if commit not found:
|
||||
- (BOOL)commit:(Commit **)commit forSHA1:(NSString *)theSHA1 error:(NSError **)error;
|
||||
|
||||
// Returns NO if commit not found:
|
||||
- (BOOL)tree:(Tree **)tree forSHA1:(NSString *)theSHA1 error:(NSError **)error;
|
||||
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly;
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 error:(NSError **)error;
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 error:(NSError **)error;
|
||||
- (NSData *)dataForSHA1s:(NSArray *)sha1s error:(NSError **)error;
|
||||
- (BOOL)commonAncestorCommitSHA1:(NSString **)ancestorSHA1 forCommitSHA1:(NSString *)commit0SHA1 andCommitSHA1:(NSString *)commit1SHA1 error:(NSError **)error;
|
||||
- (BOOL)is:(BOOL *)isAncestor commitSHA1:(NSString *)descendantSHA1 ancestorOfCommitSHA1:(NSString *)sha1 error:(NSError **)error;
|
||||
- (NSString *)localHeadS3Path;
|
||||
- (BOOL)isEncrypted;
|
||||
- (NSString *)blobsPackSetName;
|
||||
- (NSSet *)packSetNames;
|
||||
@end
|
||||
291
S3Repo.m
Normal file
291
S3Repo.m
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "ServerBlob.h"
|
||||
#import "S3Repo.h"
|
||||
#import "S3Service.h"
|
||||
#import "S3Fark.h"
|
||||
#import "SetNSError.h"
|
||||
#import "Tree.h"
|
||||
#import "Commit.h"
|
||||
#import "NSData-Encrypt.h"
|
||||
#import "DecryptedInputStream.h"
|
||||
#import "InputStreams.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "NSData-InputStream.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "HTTP.h"
|
||||
|
||||
@interface S3Repo (internal)
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 packSetName:(NSString *)thePackSetName error:(NSError **)error;
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 packSetName:(NSString *)thePackSetName searchPackOnly:(BOOL)packOnly error:(NSError **)error;
|
||||
- (BOOL)ancestorCommitSHA1sForCommitSHA1:(NSString *)commitSHA1 outArray:(NSMutableArray *)arr error:(NSError **)error;
|
||||
- (BOOL)commitSHA1:(NSString **)sha1 fromSHA1:(NSString *)fromSHA1 before:(NSDate *)date error:(NSError **)error;
|
||||
@end
|
||||
|
||||
static NSString *ERROR_DOMAIN = @"S3RepoErrorDomain";
|
||||
|
||||
@implementation S3Repo
|
||||
+ (NSString *)errorDomain {
|
||||
return ERROR_DOMAIN;
|
||||
}
|
||||
- (id)initWithS3Service:(S3Service *)theS3
|
||||
s3BucketName:(NSString *)theS3BucketName
|
||||
computerUUID:(NSString *)theComputerUUID
|
||||
bucketUUID:(NSString *)theBucketUUID
|
||||
encrypted:(BOOL)isEncrypted
|
||||
encryptionKey:(NSString *)theEncryptionKey
|
||||
fark:(S3Fark *)theFark
|
||||
ensureCacheIntegrity:(BOOL)ensure {
|
||||
if (self = [super init]) {
|
||||
s3 = [theS3 retain];
|
||||
s3BucketName = [theS3BucketName copy];
|
||||
computerUUID = [theComputerUUID copy];
|
||||
bucketUUID = [theBucketUUID copy];
|
||||
encrypted = isEncrypted;
|
||||
encryptionKey = [theEncryptionKey copy];
|
||||
fark = [theFark retain];
|
||||
ensureCacheIntegrity = ensure;
|
||||
treesPackSetName = [[NSString alloc] initWithFormat:@"%@-trees", bucketUUID];
|
||||
blobsPackSetName = [[NSString alloc] initWithFormat:@"%@-blobs", bucketUUID];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[s3 release];
|
||||
[s3BucketName release];
|
||||
[computerUUID release];
|
||||
[bucketUUID release];
|
||||
[encryptionKey release];
|
||||
[fark release];
|
||||
[treesPackSetName release];
|
||||
[blobsPackSetName release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)localHeadSHA1:(NSString **)headSHA1 error:(NSError **)error {
|
||||
*headSHA1 = nil;
|
||||
NSError *myError;
|
||||
NSData *headSHA1Data = [s3 dataAtPath:[self localHeadS3Path] error:&myError];
|
||||
if (headSHA1Data == nil && !([[myError domain] isEqualToString:[S3Service serverErrorDomain]] && [myError code] == HTTP_NOT_FOUND)) {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
if (headSHA1Data != nil) {
|
||||
*headSHA1 = [[[NSString alloc] initWithData:headSHA1Data encoding:NSUTF8StringEncoding] autorelease];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)commit:(Commit **)commit forSHA1:(NSString *)theSHA1 error:(NSError **)error {
|
||||
*commit = nil;
|
||||
NSData *data = [self dataForSHA1:theSHA1 packSetName:treesPackSetName searchPackOnly:YES error:error];
|
||||
if (data == nil) {
|
||||
HSLogDebug(@"commit data not found for %@", theSHA1);
|
||||
return NO;
|
||||
}
|
||||
id <BufferedInputStream> is = [data newInputStream];
|
||||
*commit = [[[Commit alloc] initWithBufferedInputStream:is error:error] autorelease];
|
||||
[is release];
|
||||
if (*commit == nil) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)tree:(Tree **)tree forSHA1:(NSString *)theSHA1 error:(NSError **)error {
|
||||
*tree = nil;
|
||||
NSData *data = [self dataForSHA1:theSHA1 packSetName:treesPackSetName searchPackOnly:YES error:error];
|
||||
if (data == nil) {
|
||||
HSLogDebug(@"tree data not found for %@", theSHA1);
|
||||
return NO;
|
||||
}
|
||||
id <BufferedInputStream> is = [data newInputStream];
|
||||
*tree = [[[Tree alloc] initWithBufferedInputStream:is error:error] autorelease];
|
||||
[is release];
|
||||
if (*tree == nil) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)containsBlobForSHA1:(NSString *)sha1 packSetName:(NSString *)packSetName searchPackOnly:(BOOL)searchPackOnly {
|
||||
return [fark containsBlobForSHA1:sha1 packSetName:packSetName searchPackOnly:searchPackOnly];
|
||||
}
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 error:(NSError **)error {
|
||||
NSData *data = [fark dataForSHA1:sha1 packSetName:treesPackSetName searchPackOnly:YES error:error];
|
||||
if (data == nil) {
|
||||
data = [fark dataForSHA1:sha1 packSetName:blobsPackSetName searchPackOnly:NO error:error];
|
||||
}
|
||||
if (data != nil && encrypted) {
|
||||
data = [data decryptWithCipher:ARQ_DEFAULT_CIPHER_NAME key:encryptionKey error:error];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
- (ServerBlob *)newServerBlobForSHA1:(NSString *)sha1 error:(NSError **)error {
|
||||
ServerBlob *sb = [fark newServerBlobForSHA1:sha1 packSetName:treesPackSetName searchPackOnly:NO error:error];
|
||||
if (sb == nil) {
|
||||
sb = [fark newServerBlobForSHA1:sha1 packSetName:blobsPackSetName searchPackOnly:NO error:error];
|
||||
}
|
||||
if (sb != nil && encrypted) {
|
||||
id <InputStream> is = [sb newInputStream];
|
||||
NSString *mimeType = [sb mimeType];
|
||||
NSString *downloadName = [sb downloadName];
|
||||
[sb release];
|
||||
DecryptedInputStream *dis = [[DecryptedInputStream alloc] initWithInputStream:is cipherName:ARQ_DEFAULT_CIPHER_NAME key:encryptionKey error:error];
|
||||
[is release];
|
||||
if (dis == nil) {
|
||||
return NO;
|
||||
}
|
||||
sb = [[ServerBlob alloc] initWithInputStream:dis mimeType:mimeType downloadName:downloadName];
|
||||
[dis release];
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
- (NSData *)dataForSHA1s:(NSArray *)sha1s error:(NSError **)error {
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
for (NSString *sha1 in sha1s) {
|
||||
ServerBlob *sb = [self newServerBlobForSHA1:sha1 error:error];
|
||||
if (sb == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSData *blobData = [sb slurp:error];
|
||||
[sb release];
|
||||
if (blobData == nil) {
|
||||
return NO;
|
||||
}
|
||||
//FIXME: Get rid of this extra copying of data.
|
||||
[data appendData:blobData];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
- (BOOL)commonAncestorCommitSHA1:(NSString **)ancestorSHA1 forCommitSHA1:(NSString *)commit0SHA1 andCommitSHA1:(NSString *)commit1SHA1 error:(NSError **)error {
|
||||
//FIXME: This is slow and memory-intensive!
|
||||
NSMutableArray *commit0ParentSHA1s = [[[NSMutableArray alloc] initWithObjects:commit0SHA1, nil] autorelease];
|
||||
NSMutableArray *commit1ParentSHA1s = [[[NSMutableArray alloc] initWithObjects:commit1SHA1, nil] autorelease];
|
||||
if (![self ancestorCommitSHA1sForCommitSHA1:commit0SHA1 outArray:commit0ParentSHA1s error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (![self ancestorCommitSHA1sForCommitSHA1:commit1SHA1 outArray:commit1ParentSHA1s error:error]) {
|
||||
return NO;
|
||||
}
|
||||
for (NSString *parent in commit1ParentSHA1s) {
|
||||
if ([commit0ParentSHA1s containsObject:parent]) {
|
||||
*ancestorSHA1 = parent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)is:(BOOL *)isAncestor commitSHA1:(NSString *)ancestorCommitSHA1 ancestorOfCommitSHA1:(NSString *)sha1 error:(NSError **)error {
|
||||
*isAncestor = NO;
|
||||
if ([ancestorCommitSHA1 isEqualToString:sha1]) {
|
||||
return YES;
|
||||
}
|
||||
//TODO: Get rid of recursion in this method:
|
||||
Commit *commit = nil;
|
||||
if (![self commit:&commit forSHA1:sha1 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
for (NSString *parentCommitSHA1 in [commit parentCommitSHA1s]) {
|
||||
if (![self is:isAncestor commitSHA1:parentCommitSHA1 ancestorOfCommitSHA1:ancestorCommitSHA1 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (*isAncestor) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (NSString *)localHeadS3Path {
|
||||
return [NSString stringWithFormat:@"/%@/%@/bucketdata/%@/refs/heads/master", s3BucketName, computerUUID, bucketUUID];
|
||||
}
|
||||
- (BOOL)isEncrypted {
|
||||
return encrypted;
|
||||
}
|
||||
- (NSString *)blobsPackSetName {
|
||||
return blobsPackSetName;
|
||||
}
|
||||
- (NSSet *)packSetNames {
|
||||
return [NSSet setWithObjects:blobsPackSetName, treesPackSetName, nil];
|
||||
}
|
||||
|
||||
#pragma mark NSObject protocol
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<S3Repo %p bucket %@>", self, bucketUUID];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation S3Repo (internal)
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 packSetName:(NSString *)thePackSetName error:(NSError **)error {
|
||||
return [self dataForSHA1:sha1 packSetName:thePackSetName searchPackOnly:NO error:error];
|
||||
}
|
||||
- (NSData *)dataForSHA1:(NSString *)sha1 packSetName:(NSString *)thePackSetName searchPackOnly:(BOOL)packOnly error:(NSError **)error {
|
||||
NSData *data = [fark dataForSHA1:sha1 packSetName:thePackSetName searchPackOnly:packOnly error:error];
|
||||
if (data != nil && encrypted) {
|
||||
data = [data decryptWithCipher:ARQ_DEFAULT_CIPHER_NAME key:encryptionKey error:error];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
- (BOOL)ancestorCommitSHA1sForCommitSHA1:(NSString *)commitSHA1 outArray:(NSMutableArray *)arr error:(NSError **)error {
|
||||
Commit *commit = nil;
|
||||
if (![self commit:&commit forSHA1:commitSHA1 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
for (NSString *parentCommitSHA1 in [commit parentCommitSHA1s]) {
|
||||
[arr addObject:parentCommitSHA1];
|
||||
if (![self ancestorCommitSHA1sForCommitSHA1:parentCommitSHA1 outArray:arr error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)commitSHA1:(NSString **)sha1 fromSHA1:(NSString *)fromSHA1 before:(NSDate *)date error:(NSError **)error {
|
||||
HSLogDebug(@"looking for Commit before %@", [date description]);
|
||||
*sha1 = nil;
|
||||
for (;;) {
|
||||
Commit *commit = nil;
|
||||
if (![self commit:&commit forSHA1:fromSHA1 error:error]) {
|
||||
return NO;
|
||||
}
|
||||
NSDate *creationDate = [commit creationDate];
|
||||
if ([date earlierDate:creationDate] == creationDate) {
|
||||
*sha1 = [[fromSHA1 retain] autorelease];
|
||||
HSLogDebug(@"returning Commit SHA1 %@: creationDate=%@", *sha1, creationDate);
|
||||
break;
|
||||
}
|
||||
if ([[commit parentCommitSHA1s] count] == 0) {
|
||||
break;
|
||||
}
|
||||
fromSHA1 = [[[commit parentCommitSHA1s] allObjects] objectAtIndex:0];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
92
Tree.h
Normal file
92
Tree.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Blob.h"
|
||||
#import "BufferedInputStream.h"
|
||||
#import "OutputStream.h"
|
||||
@class Node;
|
||||
@class MutableS3Repo;
|
||||
|
||||
#define CURRENT_TREE_VERSION 10
|
||||
|
||||
@interface Tree : NSObject {
|
||||
int treeVersion;
|
||||
NSString *xattrsSHA1;
|
||||
unsigned long long xattrsSize;
|
||||
NSString *aclSHA1;
|
||||
int uid;
|
||||
int gid;
|
||||
int mode;
|
||||
long long mtime_sec;
|
||||
long long mtime_nsec;
|
||||
long long flags;
|
||||
int finderFlags;
|
||||
int extendedFinderFlags;
|
||||
int st_dev;
|
||||
int st_ino;
|
||||
uint32_t st_nlink; // in struct stat, it's only 16 bits.
|
||||
int st_rdev;
|
||||
int64_t ctime_sec;
|
||||
int64_t ctime_nsec;
|
||||
int64_t createTime_sec;
|
||||
int64_t createTime_nsec;
|
||||
int64_t st_blocks;
|
||||
uint32_t st_blksize;
|
||||
NSMutableDictionary *nodes;
|
||||
}
|
||||
- (id)init;
|
||||
- (id)initWithBufferedInputStream:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
- (NSArray *)childNodeNames;
|
||||
- (Node *)childNodeWithName:(NSString *)name;
|
||||
- (BOOL)containsNodeNamed:(NSString *)name;
|
||||
|
||||
@property(readonly,copy) NSString *xattrsSHA1;
|
||||
@property(readonly) unsigned long long xattrsSize;
|
||||
@property(readonly,copy) NSString *aclSHA1;
|
||||
@property(readonly) int uid;
|
||||
@property(readonly) int gid;
|
||||
@property(readonly) int mode;
|
||||
@property(readonly) long long mtime_sec;
|
||||
@property(readonly) long long mtime_nsec;
|
||||
@property(readonly) long long flags;
|
||||
@property(readonly) int finderFlags;
|
||||
@property(readonly) int extendedFinderFlags;
|
||||
@property(readonly) int treeVersion;
|
||||
@property(readonly) int st_rdev;
|
||||
@property(readonly) long long ctime_sec;
|
||||
@property(readonly) long long ctime_nsec;
|
||||
@property(readonly) long long createTime_sec;
|
||||
@property(readonly) long long createTime_nsec;
|
||||
@property(readonly) uint32_t st_nlink;
|
||||
@property(readonly) int st_ino;
|
||||
@end
|
||||
156
Tree.m
Normal file
156
Tree.m
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "StringIO.h"
|
||||
#import "IntegerIO.h"
|
||||
#import "BooleanIO.h"
|
||||
#import "Node.h"
|
||||
#import "Tree.h"
|
||||
#import "Blob.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "RegexKitLite.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "Streams.h"
|
||||
|
||||
#define HEADER_LENGTH (8)
|
||||
|
||||
@interface Tree (internal)
|
||||
- (BOOL)readHeader:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation Tree
|
||||
@synthesize xattrsSHA1, xattrsSize, aclSHA1, uid, gid, mode, mtime_sec, mtime_nsec, flags, finderFlags, extendedFinderFlags, treeVersion, st_rdev;
|
||||
@synthesize ctime_sec, ctime_nsec, createTime_sec, createTime_nsec, st_nlink, st_ino;
|
||||
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
nodes = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (id)initWithBufferedInputStream:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
if (![self readHeader:is error:error]) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
BOOL ret = [StringIO read:&xattrsSHA1 from:is error:error]
|
||||
&& [IntegerIO readUInt64:&xattrsSize from:is error:error]
|
||||
&&[StringIO read:&aclSHA1 from:is error:error]
|
||||
&& [IntegerIO readInt32:&uid from:is error:error]
|
||||
&& [IntegerIO readInt32:&gid from:is error:error]
|
||||
&& [IntegerIO readInt32:&mode from:is error:error]
|
||||
&& [IntegerIO readInt64:&mtime_sec from:is error:error]
|
||||
&& [IntegerIO readInt64:&mtime_nsec from:is error:error]
|
||||
&& [IntegerIO readInt64:&flags from:is error:error]
|
||||
&& [IntegerIO readInt32:&finderFlags from:is error:error]
|
||||
&& [IntegerIO readInt32:&extendedFinderFlags from:is error:error]
|
||||
&& [IntegerIO readInt32:&st_dev from:is error:error]
|
||||
&& [IntegerIO readInt32:&st_ino from:is error:error]
|
||||
&& [IntegerIO readUInt32:&st_nlink from:is error:error]
|
||||
&& [IntegerIO readInt32:&st_rdev from:is error:error]
|
||||
&& [IntegerIO readInt64:&ctime_sec from:is error:error]
|
||||
&& [IntegerIO readInt64:&ctime_nsec from:is error:error]
|
||||
&& [IntegerIO readInt64:&st_blocks from:is error:error]
|
||||
&& [IntegerIO readUInt32:&st_blksize from:is error:error];
|
||||
[xattrsSHA1 retain];
|
||||
[aclSHA1 retain];
|
||||
|
||||
if (!ret) {
|
||||
goto initError;
|
||||
}
|
||||
|
||||
unsigned int nodeCount;
|
||||
if (![IntegerIO readUInt32:&nodeCount from:is error:error]) {
|
||||
goto initError;
|
||||
}
|
||||
nodes = [[NSMutableDictionary alloc] init];
|
||||
for (unsigned int i = 0; i < nodeCount; i++) {
|
||||
NSString *nodeName;
|
||||
if (![StringIO read:&nodeName from:is error:error]) {
|
||||
goto initError;
|
||||
}
|
||||
Node *node = [[Node alloc] initWithInputStream:is treeVersion:treeVersion error:error];
|
||||
if (!node) {
|
||||
goto initError;
|
||||
}
|
||||
[nodes setObject:node forKey:nodeName];
|
||||
[node release];
|
||||
}
|
||||
goto initDone;
|
||||
initError:
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
initDone:
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[xattrsSHA1 release];
|
||||
[aclSHA1 release];
|
||||
[nodes release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSArray *)childNodeNames {
|
||||
return [nodes allKeys];
|
||||
}
|
||||
- (Node *)childNodeWithName:(NSString *)name {
|
||||
return [nodes objectForKey:name];
|
||||
}
|
||||
- (BOOL)containsNodeNamed:(NSString *)name {
|
||||
return [nodes objectForKey:name] != nil;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation Tree (internal)
|
||||
- (BOOL)readHeader:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
unsigned char *headerBytes = [is readExactly:HEADER_LENGTH error:error];
|
||||
if (headerBytes == NULL) {
|
||||
return NO;
|
||||
}
|
||||
NSString *header = [[[NSString alloc] initWithBytes:headerBytes length:HEADER_LENGTH encoding:NSASCIIStringEncoding] autorelease];
|
||||
NSRange versionRange = [header rangeOfRegex:@"^TreeV(\\d{3})$" capture:1];
|
||||
treeVersion = 0;
|
||||
if (versionRange.location != NSNotFound) {
|
||||
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
|
||||
NSNumber *number = [nf numberFromString:[header substringWithRange:versionRange]];
|
||||
treeVersion = [number intValue];
|
||||
[nf release];
|
||||
}
|
||||
if (treeVersion != CURRENT_TREE_VERSION) {
|
||||
SETNSERROR(@"TreeErrorDomain", ERROR_INVALID_OBJECT_VERSION, @"invalid Tree header: %@", header);
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
45
XAttrSet.h
Normal file
45
XAttrSet.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Blob.h"
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface XAttrSet : NSObject {
|
||||
NSMutableDictionary *xattrs;
|
||||
}
|
||||
- (id)initWithPath:(NSString *)thePath error:(NSError **)error;
|
||||
- (id)initWithBufferedInputStream:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
- (NSUInteger)count;
|
||||
- (NSArray *)names;
|
||||
- (BOOL)applyToFile:(NSString *)path error:(NSError **)error;
|
||||
@end
|
||||
190
XAttrSet.m
Normal file
190
XAttrSet.m
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/xattr.h>
|
||||
#import "XAttrSet.h"
|
||||
#import "StringIO.h"
|
||||
#import "DataIO.h"
|
||||
#import "IntegerIO.h"
|
||||
#import "Blob.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "Streams.h"
|
||||
|
||||
#define HEADER_LENGTH (12)
|
||||
|
||||
@interface XAttrSet (internal)
|
||||
- (BOOL)loadFromPath:(NSString *)thePath error:(NSError **)error;
|
||||
- (BOOL)loadFromInputStream:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation XAttrSet
|
||||
- (id)initWithPath:(NSString *)thePath error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
xattrs = [[NSMutableDictionary alloc] init];
|
||||
if (![self loadFromPath:thePath error:error]) {
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (id)initWithBufferedInputStream:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
xattrs = [[NSMutableDictionary alloc] init];
|
||||
if (![self loadFromInputStream:is error:error]) {
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[xattrs release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSUInteger)count {
|
||||
return [xattrs count];
|
||||
}
|
||||
- (NSArray *)names {
|
||||
return [xattrs allKeys];
|
||||
}
|
||||
- (BOOL)applyToFile:(NSString *)path error:(NSError **)error {
|
||||
XAttrSet *current = [[[XAttrSet alloc] initWithPath:path error:error] autorelease];
|
||||
if (!current) {
|
||||
return NO;
|
||||
}
|
||||
const char *pathChars = [path fileSystemRepresentation];
|
||||
for (NSString *name in [current names]) {
|
||||
if (removexattr(pathChars, [name UTF8String], XATTR_NOFOLLOW) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"removexattr: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
for (NSString *key in [xattrs allKeys]) {
|
||||
NSData *value = [xattrs objectForKey:key];
|
||||
if (setxattr(pathChars,
|
||||
[key UTF8String],
|
||||
[value bytes],
|
||||
[value length],
|
||||
0,
|
||||
XATTR_NOFOLLOW) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"setxattr: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation XAttrSet (internal)
|
||||
- (BOOL)loadFromPath:(NSString *)thePath error:(NSError **)error {
|
||||
NSDictionary *attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:thePath error:error];
|
||||
if (attribs == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSString *fileType = [attribs objectForKey:NSFileType];
|
||||
if (![fileType isEqualToString:NSFileTypeSocket]
|
||||
&& ![fileType isEqualToString:NSFileTypeBlockSpecial]
|
||||
&& ![fileType isEqualToString:NSFileTypeCharacterSpecial]
|
||||
&& ![fileType isEqualToString:NSFileTypeUnknown]) {
|
||||
const char *path = [thePath fileSystemRepresentation];
|
||||
ssize_t xattrsize = listxattr(path, NULL, 0, XATTR_NOFOLLOW);
|
||||
if (xattrsize == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
if (xattrsize > 0) {
|
||||
char *xattrbuf = (char *)malloc(xattrsize);
|
||||
xattrsize = listxattr(path, xattrbuf, xattrsize, XATTR_NOFOLLOW);
|
||||
if (xattrsize == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s", strerror(errno));
|
||||
free(xattrbuf);
|
||||
return NO;
|
||||
}
|
||||
for (char *name = xattrbuf; name < (xattrbuf + xattrsize); name += strlen(name) + 1) {
|
||||
NSString *theName = [NSString stringWithUTF8String:name];
|
||||
ssize_t valuesize = getxattr(path, name, NULL, 0, 0, XATTR_NOFOLLOW);
|
||||
NSData *xattrData = nil;
|
||||
if (valuesize == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"Error reading extended attribute %s: %s", name, strerror(errno));
|
||||
free(xattrbuf);
|
||||
return NO;
|
||||
}
|
||||
if (valuesize > 0) {
|
||||
void *value = malloc(valuesize);
|
||||
if (getxattr(path, name, value, valuesize, 0, XATTR_NOFOLLOW) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"getxattr: %s", strerror(errno));
|
||||
free(value);
|
||||
free(xattrbuf);
|
||||
return NO;
|
||||
}
|
||||
xattrData = [NSData dataWithBytes:value length:valuesize];
|
||||
free(value);
|
||||
} else {
|
||||
xattrData = [NSData data];
|
||||
}
|
||||
[xattrs setObject:xattrData forKey:theName];
|
||||
}
|
||||
free(xattrbuf);
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)loadFromInputStream:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
unsigned char *headerBytes = [is readExactly:HEADER_LENGTH error:error];
|
||||
if (headerBytes == NULL) {
|
||||
return NO;
|
||||
}
|
||||
if (strncmp((const char *)headerBytes, "XAttrSetV002", HEADER_LENGTH)) {
|
||||
SETNSERROR(@"XAttrSetErrorDomain", ERROR_INVALID_OBJECT_VERSION, @"invalid XAttrSet header");
|
||||
return NO;
|
||||
}
|
||||
uint64_t count;
|
||||
if (![IntegerIO readUInt64:&count from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
for (uint64_t i = 0; i < count; i++) {
|
||||
NSString *name;
|
||||
if (![StringIO read:&name from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
NSData *value;
|
||||
if (![DataIO read:&value from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
[xattrs setObject:value forKey:name];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
69
arq_restore.m
Normal file
69
arq_restore.m
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ArqRestoreCommand.h"
|
||||
#import "ArqFolder.h"
|
||||
|
||||
static void printUsage(const char *exeName) {
|
||||
fprintf(stderr, "\t%s\n", exeName);
|
||||
fprintf(stderr, "\t%s /s3bucket/computerUUID/folderUUID\n", exeName);
|
||||
}
|
||||
int main (int argc, const char * argv[]) {
|
||||
setHSLogLevel(HSLOG_LEVEL_ERROR);
|
||||
char *exePath = strdup(argv[0]);
|
||||
char *exeName = basename(exePath);
|
||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||
ArqRestoreCommand *cmd = [[[ArqRestoreCommand alloc] init] autorelease];
|
||||
int ret = 0;
|
||||
NSError *error = nil;
|
||||
if (argc == 1) {
|
||||
if (![cmd printArqFolders:&error]) {
|
||||
NSLog(@"%@", [error localizedDescription]);
|
||||
ret = 1;
|
||||
} else {
|
||||
printf("\nType %s <s3 path> to restore\n", exeName);
|
||||
}
|
||||
} else if (argc == 2) {
|
||||
if (![cmd restorePath:[NSString stringWithUTF8String:argv[1]] error:&error]) {
|
||||
NSLog(@"%@", [error localizedDescription]);
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
printUsage(exeName);
|
||||
ret = 1;
|
||||
}
|
||||
[pool drain];
|
||||
free(exePath);
|
||||
return ret;
|
||||
}
|
||||
2
arq_restore.xcodeproj/.gitignore
vendored
Normal file
2
arq_restore.xcodeproj/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
stefan.mode1v3
|
||||
stefan.pbxuser
|
||||
825
arq_restore.xcodeproj/project.pbxproj
Normal file
825
arq_restore.xcodeproj/project.pbxproj
Normal file
|
|
@ -0,0 +1,825 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 45;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8DD76F9A0486AA7600D96B5E /* arq_restore.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* arq_restore.m */; settings = {ATTRIBUTES = (); }; };
|
||||
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
|
||||
F805B54D1160D3E6007EC01E /* ArqRestoreCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B54C1160D3E6007EC01E /* ArqRestoreCommand.m */; };
|
||||
F805B7211160D9C2007EC01E /* HSLog.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7201160D9C2007EC01E /* HSLog.m */; };
|
||||
F805B7301160DBE9007EC01E /* ArqFolder.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B72F1160DBE9007EC01E /* ArqFolder.m */; };
|
||||
F805B7531160DCFE007EC01E /* ArrayNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7421160DCFE007EC01E /* ArrayNode.m */; };
|
||||
F805B7541160DCFE007EC01E /* BooleanNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7441160DCFE007EC01E /* BooleanNode.m */; };
|
||||
F805B7551160DCFE007EC01E /* DictNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7461160DCFE007EC01E /* DictNode.m */; };
|
||||
F805B7561160DCFE007EC01E /* IntegerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7481160DCFE007EC01E /* IntegerNode.m */; };
|
||||
F805B7571160DCFE007EC01E /* RealNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B74C1160DCFE007EC01E /* RealNode.m */; };
|
||||
F805B7581160DCFE007EC01E /* StringNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B74E1160DCFE007EC01E /* StringNode.m */; };
|
||||
F805B7591160DCFE007EC01E /* XMLPListReader.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7501160DCFE007EC01E /* XMLPListReader.m */; };
|
||||
F805B75A1160DCFE007EC01E /* XMLPListWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7521160DCFE007EC01E /* XMLPListWriter.m */; };
|
||||
F805B7821160DD60007EC01E /* HTTPConnection_S3.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7691160DD60007EC01E /* HTTPConnection_S3.m */; };
|
||||
F805B7831160DD60007EC01E /* NSError_S3.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B76B1160DD60007EC01E /* NSError_S3.m */; };
|
||||
F805B7841160DD60007EC01E /* PathReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B76D1160DD60007EC01E /* PathReceiver.m */; };
|
||||
F805B7851160DD60007EC01E /* S3AuthorizationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B76F1160DD60007EC01E /* S3AuthorizationParameters.m */; };
|
||||
F805B7861160DD60007EC01E /* S3AuthorizationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7711160DD60007EC01E /* S3AuthorizationProvider.m */; };
|
||||
F805B7871160DD60007EC01E /* S3Lister.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7731160DD60007EC01E /* S3Lister.m */; };
|
||||
F805B7881160DD60007EC01E /* S3ObjectMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7751160DD60007EC01E /* S3ObjectMetadata.m */; };
|
||||
F805B7891160DD60007EC01E /* S3ObjectReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7771160DD60007EC01E /* S3ObjectReceiver.m */; };
|
||||
F805B78B1160DD60007EC01E /* S3Request.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B77C1160DD60007EC01E /* S3Request.m */; };
|
||||
F805B78C1160DD60007EC01E /* S3Service.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B77E1160DD60007EC01E /* S3Service.m */; };
|
||||
F805B78D1160DD60007EC01E /* S3Signature.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7801160DD60007EC01E /* S3Signature.m */; };
|
||||
F805B7A91160DEF2007EC01E /* RegexKitLite.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7A81160DEF2007EC01E /* RegexKitLite.m */; };
|
||||
F805B7BA1160E3AF007EC01E /* Blob.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7B91160E3AF007EC01E /* Blob.m */; };
|
||||
F805B7D11160E445007EC01E /* HTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7CC1160E445007EC01E /* HTTPConnection.m */; };
|
||||
F805B7D21160E445007EC01E /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7CE1160E445007EC01E /* HTTPRequest.m */; };
|
||||
F805B7D31160E445007EC01E /* HTTPResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7D01160E445007EC01E /* HTTPResponse.m */; };
|
||||
F805B7D81160E456007EC01E /* BlobACL.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7D71160E456007EC01E /* BlobACL.m */; };
|
||||
F805B7E11160E48B007EC01E /* ServerBlob.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7E01160E48B007EC01E /* ServerBlob.m */; };
|
||||
F805B7FB1160E73D007EC01E /* RFC2616DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7FA1160E73D007EC01E /* RFC2616DateFormatter.m */; };
|
||||
F805B7FE1160E764007EC01E /* RFC822.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7FD1160E764007EC01E /* RFC822.m */; };
|
||||
F805B81B1160E838007EC01E /* InputStreams.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B81A1160E838007EC01E /* InputStreams.m */; };
|
||||
F805B8251160E857007EC01E /* ChunkedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8221160E857007EC01E /* ChunkedInputStream.m */; };
|
||||
F805B8261160E857007EC01E /* FixedLengthInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8241160E857007EC01E /* FixedLengthInputStream.m */; };
|
||||
F805B82B1160E861007EC01E /* FDInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8281160E861007EC01E /* FDInputStream.m */; };
|
||||
F805B82C1160E861007EC01E /* FDOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B82A1160E861007EC01E /* FDOutputStream.m */; };
|
||||
F805B82F1160E86E007EC01E /* DataInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B82E1160E86E007EC01E /* DataInputStream.m */; };
|
||||
F805B8321160E878007EC01E /* Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8311160E878007EC01E /* Writer.m */; };
|
||||
F805B83B1160E8DD007EC01E /* NSData-InputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B83A1160E8DD007EC01E /* NSData-InputStream.m */; };
|
||||
F805B83F1160E900007EC01E /* StreamPairFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B83E1160E900007EC01E /* StreamPairFactory.m */; };
|
||||
F805B8421160E90F007EC01E /* Streams.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8411160E90F007EC01E /* Streams.m */; };
|
||||
F805B8531160E9B0007EC01E /* CFStreamPair.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8521160E9B0007EC01E /* CFStreamPair.m */; };
|
||||
F805B85A1160E9C9007EC01E /* CFStreamInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8571160E9C9007EC01E /* CFStreamInputStream.m */; };
|
||||
F805B85B1160E9C9007EC01E /* CFStreamOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8591160E9C9007EC01E /* CFStreamOutputStream.m */; };
|
||||
F805B8601160E9F0007EC01E /* DNS_SDErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B85F1160E9F0007EC01E /* DNS_SDErrors.m */; };
|
||||
F805B8651160EA15007EC01E /* NSXMLNode_extra.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8641160EA15007EC01E /* NSXMLNode_extra.m */; };
|
||||
F805B86A1160EA83007EC01E /* NSData-Base64Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B8691160EA83007EC01E /* NSData-Base64Extensions.m */; };
|
||||
F805B86F1160EAC1007EC01E /* DataInputStreamFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B86E1160EAC1007EC01E /* DataInputStreamFactory.m */; };
|
||||
F805B8891160EB39007EC01E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8881160EB39007EC01E /* libcrypto.dylib */; };
|
||||
F805B88B1160EB3A007EC01E /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B88A1160EB39007EC01E /* libicucore.dylib */; };
|
||||
F805B88F1160EB45007EC01E /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B88E1160EB45007EC01E /* libssl.dylib */; };
|
||||
F805B8931160EB4E007EC01E /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8921160EB4E007EC01E /* SystemConfiguration.framework */; };
|
||||
F805B8A11160EBAA007EC01E /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8A01160EBAA007EC01E /* CoreFoundation.framework */; };
|
||||
F805B8C21160EC41007EC01E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8C11160EC41007EC01E /* Security.framework */; };
|
||||
F805B8CE1160ECD7007EC01E /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8CD1160ECD7007EC01E /* CoreServices.framework */; };
|
||||
F8D678001160F26A00CC270E /* Restorer.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D677FF1160F26A00CC270E /* Restorer.m */; };
|
||||
F8D678171160F4E300CC270E /* S3Fark.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678141160F4E300CC270E /* S3Fark.m */; };
|
||||
F8D678181160F4E300CC270E /* S3Repo.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678161160F4E300CC270E /* S3Repo.m */; };
|
||||
F8D6781D1160F4FD00CC270E /* SHA1Hash.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6781C1160F4FD00CC270E /* SHA1Hash.m */; };
|
||||
F8D6782D1160F5D000CC270E /* PackSetSet.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6782A1160F5D000CC270E /* PackSetSet.m */; };
|
||||
F8D6782E1160F5D000CC270E /* PackSet.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6782C1160F5D000CC270E /* PackSet.m */; };
|
||||
F8D678331160F62E00CC270E /* ArqUserLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678321160F62E00CC270E /* ArqUserLibrary.m */; };
|
||||
F8D6783C1160F70100CC270E /* PackIndexEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6783B1160F70100CC270E /* PackIndexEntry.m */; };
|
||||
F8D678451160F74A00CC270E /* DiskPack.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678421160F74A00CC270E /* DiskPack.m */; };
|
||||
F8D678461160F74A00CC270E /* DiskPackIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678441160F74A00CC270E /* DiskPackIndex.m */; };
|
||||
F8D6785F1160F7CF00CC270E /* Commit.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6785C1160F7CF00CC270E /* Commit.m */; };
|
||||
F8D678601160F7CF00CC270E /* Tree.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6785E1160F7CF00CC270E /* Tree.m */; };
|
||||
F8D678651160F7FE00CC270E /* NSData-Encrypt.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678641160F7FE00CC270E /* NSData-Encrypt.m */; };
|
||||
F8D6786A1160F81100CC270E /* OpenSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678691160F81100CC270E /* OpenSSL.m */; };
|
||||
F8D6786F1160F84600CC270E /* DecryptedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6786E1160F84600CC270E /* DecryptedInputStream.m */; };
|
||||
F8D678741160F85D00CC270E /* CryptInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678731160F85D00CC270E /* CryptInputStream.m */; };
|
||||
F8D678771160F86E00CC270E /* FileInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678761160F86E00CC270E /* FileInputStream.m */; };
|
||||
F8D678821160F8A000CC270E /* DataIO.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678791160F8A000CC270E /* DataIO.m */; };
|
||||
F8D678831160F8A000CC270E /* DateIO.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6787B1160F8A000CC270E /* DateIO.m */; };
|
||||
F8D678841160F8A000CC270E /* DoubleIO.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6787D1160F8A000CC270E /* DoubleIO.m */; };
|
||||
F8D678851160F8A000CC270E /* IntegerIO.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6787F1160F8A000CC270E /* IntegerIO.m */; };
|
||||
F8D678861160F8A000CC270E /* StringIO.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678811160F8A000CC270E /* StringIO.m */; };
|
||||
F8D678891160F8CD00CC270E /* NSString_extra.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678881160F8CD00CC270E /* NSString_extra.m */; };
|
||||
F8D6788C1160F8E500CC270E /* BinarySHA1.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6788B1160F8E500CC270E /* BinarySHA1.m */; };
|
||||
F8D6789A1160FA2A00CC270E /* NSFileManager_extra.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678991160FA2A00CC270E /* NSFileManager_extra.m */; };
|
||||
F8D6789D1160FA3900CC270E /* FileOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6789C1160FA3900CC270E /* FileOutputStream.m */; };
|
||||
F8D678A01160FA4800CC270E /* FileInputStreamFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D6789F1160FA4800CC270E /* FileInputStreamFactory.m */; };
|
||||
F8D678A51160FA5F00CC270E /* BooleanIO.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678A41160FA5F00CC270E /* BooleanIO.m */; };
|
||||
F8D678A81160FA6A00CC270E /* EncryptedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678A71160FA6A00CC270E /* EncryptedInputStream.m */; };
|
||||
F8D678AF1160FAD900CC270E /* CommitFailedFile.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678AE1160FAD900CC270E /* CommitFailedFile.m */; };
|
||||
F8D678B81160FB2100CC270E /* Node.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D678B71160FB2100CC270E /* Node.m */; };
|
||||
F8D67CEB1161363A00CC270E /* FileAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D67CEA1161363A00CC270E /* FileAttributes.m */; };
|
||||
F8D67CF21161366100CC270E /* XAttrSet.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D67CF11161366100CC270E /* XAttrSet.m */; };
|
||||
F8D67D071161384100CC270E /* FileACL.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D67D041161384100CC270E /* FileACL.m */; };
|
||||
F8D67D081161384100CC270E /* OSStatusDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D67D061161384100CC270E /* OSStatusDescription.m */; };
|
||||
F8D67F701161443600CC270E /* RestoreNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D67F6F1161443600CC270E /* RestoreNode.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 8;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
08FB7796FE84155DC02AAC07 /* arq_restore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = arq_restore.m; sourceTree = "<group>"; };
|
||||
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
32A70AAB03705E1F00C91783 /* arq_restore_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arq_restore_Prefix.pch; sourceTree = "<group>"; };
|
||||
8DD76FA10486AA7600D96B5E /* arq_restore */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = arq_restore; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F805B54B1160D3E6007EC01E /* ArqRestoreCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArqRestoreCommand.h; sourceTree = "<group>"; };
|
||||
F805B54C1160D3E6007EC01E /* ArqRestoreCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArqRestoreCommand.m; sourceTree = "<group>"; };
|
||||
F805B71F1160D9C2007EC01E /* HSLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSLog.h; sourceTree = "<group>"; };
|
||||
F805B7201160D9C2007EC01E /* HSLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSLog.m; sourceTree = "<group>"; };
|
||||
F805B72E1160DBE9007EC01E /* ArqFolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArqFolder.h; sourceTree = "<group>"; };
|
||||
F805B72F1160DBE9007EC01E /* ArqFolder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArqFolder.m; sourceTree = "<group>"; };
|
||||
F805B7411160DCFE007EC01E /* ArrayNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayNode.h; sourceTree = "<group>"; };
|
||||
F805B7421160DCFE007EC01E /* ArrayNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArrayNode.m; sourceTree = "<group>"; };
|
||||
F805B7431160DCFE007EC01E /* BooleanNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BooleanNode.h; sourceTree = "<group>"; };
|
||||
F805B7441160DCFE007EC01E /* BooleanNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BooleanNode.m; sourceTree = "<group>"; };
|
||||
F805B7451160DCFE007EC01E /* DictNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DictNode.h; sourceTree = "<group>"; };
|
||||
F805B7461160DCFE007EC01E /* DictNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DictNode.m; sourceTree = "<group>"; };
|
||||
F805B7471160DCFE007EC01E /* IntegerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntegerNode.h; sourceTree = "<group>"; };
|
||||
F805B7481160DCFE007EC01E /* IntegerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IntegerNode.m; sourceTree = "<group>"; };
|
||||
F805B7491160DCFE007EC01E /* PListNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PListNode.h; sourceTree = "<group>"; };
|
||||
F805B74A1160DCFE007EC01E /* PListNodeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PListNodeType.h; sourceTree = "<group>"; };
|
||||
F805B74B1160DCFE007EC01E /* RealNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealNode.h; sourceTree = "<group>"; };
|
||||
F805B74C1160DCFE007EC01E /* RealNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RealNode.m; sourceTree = "<group>"; };
|
||||
F805B74D1160DCFE007EC01E /* StringNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringNode.h; sourceTree = "<group>"; };
|
||||
F805B74E1160DCFE007EC01E /* StringNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StringNode.m; sourceTree = "<group>"; };
|
||||
F805B74F1160DCFE007EC01E /* XMLPListReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XMLPListReader.h; sourceTree = "<group>"; };
|
||||
F805B7501160DCFE007EC01E /* XMLPListReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XMLPListReader.m; sourceTree = "<group>"; };
|
||||
F805B7511160DCFE007EC01E /* XMLPListWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XMLPListWriter.h; sourceTree = "<group>"; };
|
||||
F805B7521160DCFE007EC01E /* XMLPListWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XMLPListWriter.m; sourceTree = "<group>"; };
|
||||
F805B7681160DD60007EC01E /* HTTPConnection_S3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPConnection_S3.h; sourceTree = "<group>"; };
|
||||
F805B7691160DD60007EC01E /* HTTPConnection_S3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPConnection_S3.m; sourceTree = "<group>"; };
|
||||
F805B76A1160DD60007EC01E /* NSError_S3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSError_S3.h; sourceTree = "<group>"; };
|
||||
F805B76B1160DD60007EC01E /* NSError_S3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSError_S3.m; sourceTree = "<group>"; };
|
||||
F805B76C1160DD60007EC01E /* PathReceiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PathReceiver.h; sourceTree = "<group>"; };
|
||||
F805B76D1160DD60007EC01E /* PathReceiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PathReceiver.m; sourceTree = "<group>"; };
|
||||
F805B76E1160DD60007EC01E /* S3AuthorizationParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3AuthorizationParameters.h; sourceTree = "<group>"; };
|
||||
F805B76F1160DD60007EC01E /* S3AuthorizationParameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3AuthorizationParameters.m; sourceTree = "<group>"; };
|
||||
F805B7701160DD60007EC01E /* S3AuthorizationProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3AuthorizationProvider.h; sourceTree = "<group>"; };
|
||||
F805B7711160DD60007EC01E /* S3AuthorizationProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3AuthorizationProvider.m; sourceTree = "<group>"; };
|
||||
F805B7721160DD60007EC01E /* S3Lister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3Lister.h; sourceTree = "<group>"; };
|
||||
F805B7731160DD60007EC01E /* S3Lister.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3Lister.m; sourceTree = "<group>"; };
|
||||
F805B7741160DD60007EC01E /* S3ObjectMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3ObjectMetadata.h; sourceTree = "<group>"; };
|
||||
F805B7751160DD60007EC01E /* S3ObjectMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3ObjectMetadata.m; sourceTree = "<group>"; };
|
||||
F805B7761160DD60007EC01E /* S3ObjectReceiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3ObjectReceiver.h; sourceTree = "<group>"; };
|
||||
F805B7771160DD60007EC01E /* S3ObjectReceiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3ObjectReceiver.m; sourceTree = "<group>"; };
|
||||
F805B77A1160DD60007EC01E /* S3Receiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3Receiver.h; sourceTree = "<group>"; };
|
||||
F805B77B1160DD60007EC01E /* S3Request.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3Request.h; sourceTree = "<group>"; };
|
||||
F805B77C1160DD60007EC01E /* S3Request.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3Request.m; sourceTree = "<group>"; };
|
||||
F805B77D1160DD60007EC01E /* S3Service.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3Service.h; sourceTree = "<group>"; };
|
||||
F805B77E1160DD60007EC01E /* S3Service.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3Service.m; sourceTree = "<group>"; };
|
||||
F805B77F1160DD60007EC01E /* S3Signature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3Signature.h; sourceTree = "<group>"; };
|
||||
F805B7801160DD60007EC01E /* S3Signature.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3Signature.m; sourceTree = "<group>"; };
|
||||
F805B7A71160DEF2007EC01E /* RegexKitLite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegexKitLite.h; sourceTree = "<group>"; };
|
||||
F805B7A81160DEF2007EC01E /* RegexKitLite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegexKitLite.m; sourceTree = "<group>"; };
|
||||
F805B7B81160E3AF007EC01E /* Blob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Blob.h; sourceTree = "<group>"; };
|
||||
F805B7B91160E3AF007EC01E /* Blob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Blob.m; sourceTree = "<group>"; };
|
||||
F805B7CA1160E445007EC01E /* HTTP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTP.h; sourceTree = "<group>"; };
|
||||
F805B7CB1160E445007EC01E /* HTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPConnection.h; sourceTree = "<group>"; };
|
||||
F805B7CC1160E445007EC01E /* HTTPConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPConnection.m; sourceTree = "<group>"; };
|
||||
F805B7CD1160E445007EC01E /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; };
|
||||
F805B7CE1160E445007EC01E /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = "<group>"; };
|
||||
F805B7CF1160E445007EC01E /* HTTPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPResponse.h; sourceTree = "<group>"; };
|
||||
F805B7D01160E445007EC01E /* HTTPResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPResponse.m; sourceTree = "<group>"; };
|
||||
F805B7D61160E456007EC01E /* BlobACL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlobACL.h; sourceTree = "<group>"; };
|
||||
F805B7D71160E456007EC01E /* BlobACL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlobACL.m; sourceTree = "<group>"; };
|
||||
F805B7DE1160E48B007EC01E /* NSErrorCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSErrorCodes.h; sourceTree = "<group>"; };
|
||||
F805B7DF1160E48B007EC01E /* ServerBlob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerBlob.h; sourceTree = "<group>"; };
|
||||
F805B7E01160E48B007EC01E /* ServerBlob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerBlob.m; sourceTree = "<group>"; };
|
||||
F805B7F91160E73D007EC01E /* RFC2616DateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RFC2616DateFormatter.h; sourceTree = "<group>"; };
|
||||
F805B7FA1160E73D007EC01E /* RFC2616DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RFC2616DateFormatter.m; sourceTree = "<group>"; };
|
||||
F805B7FC1160E764007EC01E /* RFC822.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RFC822.h; sourceTree = "<group>"; };
|
||||
F805B7FD1160E764007EC01E /* RFC822.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RFC822.m; sourceTree = "<group>"; };
|
||||
F805B80B1160E7C3007EC01E /* InputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputStream.h; sourceTree = "<group>"; };
|
||||
F805B8191160E838007EC01E /* InputStreams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputStreams.h; sourceTree = "<group>"; };
|
||||
F805B81A1160E838007EC01E /* InputStreams.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InputStreams.m; sourceTree = "<group>"; };
|
||||
F805B8211160E857007EC01E /* ChunkedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChunkedInputStream.h; sourceTree = "<group>"; };
|
||||
F805B8221160E857007EC01E /* ChunkedInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChunkedInputStream.m; sourceTree = "<group>"; };
|
||||
F805B8231160E857007EC01E /* FixedLengthInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FixedLengthInputStream.h; sourceTree = "<group>"; };
|
||||
F805B8241160E857007EC01E /* FixedLengthInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FixedLengthInputStream.m; sourceTree = "<group>"; };
|
||||
F805B8271160E861007EC01E /* FDInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FDInputStream.h; sourceTree = "<group>"; };
|
||||
F805B8281160E861007EC01E /* FDInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FDInputStream.m; sourceTree = "<group>"; };
|
||||
F805B8291160E861007EC01E /* FDOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FDOutputStream.h; sourceTree = "<group>"; };
|
||||
F805B82A1160E861007EC01E /* FDOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FDOutputStream.m; sourceTree = "<group>"; };
|
||||
F805B82D1160E86E007EC01E /* DataInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataInputStream.h; sourceTree = "<group>"; };
|
||||
F805B82E1160E86E007EC01E /* DataInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataInputStream.m; sourceTree = "<group>"; };
|
||||
F805B8301160E878007EC01E /* Writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Writer.h; sourceTree = "<group>"; };
|
||||
F805B8311160E878007EC01E /* Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Writer.m; sourceTree = "<group>"; };
|
||||
F805B8331160E882007EC01E /* BufferedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BufferedInputStream.h; sourceTree = "<group>"; };
|
||||
F805B8361160E8A0007EC01E /* OutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputStream.h; sourceTree = "<group>"; };
|
||||
F805B8391160E8DD007EC01E /* NSData-InputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData-InputStream.h"; sourceTree = "<group>"; };
|
||||
F805B83A1160E8DD007EC01E /* NSData-InputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData-InputStream.m"; sourceTree = "<group>"; };
|
||||
F805B83C1160E900007EC01E /* StreamPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StreamPair.h; sourceTree = "<group>"; };
|
||||
F805B83D1160E900007EC01E /* StreamPairFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StreamPairFactory.h; sourceTree = "<group>"; };
|
||||
F805B83E1160E900007EC01E /* StreamPairFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StreamPairFactory.m; sourceTree = "<group>"; };
|
||||
F805B8401160E90F007EC01E /* Streams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Streams.h; sourceTree = "<group>"; };
|
||||
F805B8411160E90F007EC01E /* Streams.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Streams.m; sourceTree = "<group>"; };
|
||||
F805B8511160E9B0007EC01E /* CFStreamPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFStreamPair.h; sourceTree = "<group>"; };
|
||||
F805B8521160E9B0007EC01E /* CFStreamPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CFStreamPair.m; sourceTree = "<group>"; };
|
||||
F805B8561160E9C9007EC01E /* CFStreamInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFStreamInputStream.h; sourceTree = "<group>"; };
|
||||
F805B8571160E9C9007EC01E /* CFStreamInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CFStreamInputStream.m; sourceTree = "<group>"; };
|
||||
F805B8581160E9C9007EC01E /* CFStreamOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFStreamOutputStream.h; sourceTree = "<group>"; };
|
||||
F805B8591160E9C9007EC01E /* CFStreamOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CFStreamOutputStream.m; sourceTree = "<group>"; };
|
||||
F805B85E1160E9F0007EC01E /* DNS_SDErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS_SDErrors.h; sourceTree = "<group>"; };
|
||||
F805B85F1160E9F0007EC01E /* DNS_SDErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNS_SDErrors.m; sourceTree = "<group>"; };
|
||||
F805B8631160EA15007EC01E /* NSXMLNode_extra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSXMLNode_extra.h; sourceTree = "<group>"; };
|
||||
F805B8641160EA15007EC01E /* NSXMLNode_extra.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSXMLNode_extra.m; sourceTree = "<group>"; };
|
||||
F805B8661160EA36007EC01E /* InputStreamFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputStreamFactory.h; sourceTree = "<group>"; };
|
||||
F805B8681160EA83007EC01E /* NSData-Base64Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData-Base64Extensions.h"; sourceTree = "<group>"; };
|
||||
F805B8691160EA83007EC01E /* NSData-Base64Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData-Base64Extensions.m"; sourceTree = "<group>"; };
|
||||
F805B86D1160EAC1007EC01E /* DataInputStreamFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataInputStreamFactory.h; sourceTree = "<group>"; };
|
||||
F805B86E1160EAC1007EC01E /* DataInputStreamFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataInputStreamFactory.m; sourceTree = "<group>"; };
|
||||
F805B8881160EB39007EC01E /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; };
|
||||
F805B88A1160EB39007EC01E /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
|
||||
F805B88E1160EB45007EC01E /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = usr/lib/libssl.dylib; sourceTree = SDKROOT; };
|
||||
F805B8921160EB4E007EC01E /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||
F805B8981160EB71007EC01E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||
F805B8A01160EBAA007EC01E /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
||||
F805B8BB1160EC38007EC01E /* SecurityFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityFoundation.framework; path = System/Library/Frameworks/SecurityFoundation.framework; sourceTree = SDKROOT; };
|
||||
F805B8C11160EC41007EC01E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||
F805B8C51160EC4E007EC01E /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
F805B8CD1160ECD7007EC01E /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
|
||||
F8D6763E1160F22800CC270E /* SetNSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetNSError.h; sourceTree = "<group>"; };
|
||||
F8D677FE1160F26A00CC270E /* Restorer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Restorer.h; sourceTree = "<group>"; };
|
||||
F8D677FF1160F26A00CC270E /* Restorer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Restorer.m; sourceTree = "<group>"; };
|
||||
F8D678131160F4E300CC270E /* S3Fark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3Fark.h; sourceTree = "<group>"; };
|
||||
F8D678141160F4E300CC270E /* S3Fark.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3Fark.m; sourceTree = "<group>"; };
|
||||
F8D678151160F4E300CC270E /* S3Repo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S3Repo.h; sourceTree = "<group>"; };
|
||||
F8D678161160F4E300CC270E /* S3Repo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = S3Repo.m; sourceTree = "<group>"; };
|
||||
F8D6781B1160F4FD00CC270E /* SHA1Hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHA1Hash.h; sourceTree = "<group>"; };
|
||||
F8D6781C1160F4FD00CC270E /* SHA1Hash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHA1Hash.m; sourceTree = "<group>"; };
|
||||
F8D678291160F5D000CC270E /* PackSetSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PackSetSet.h; sourceTree = "<group>"; };
|
||||
F8D6782A1160F5D000CC270E /* PackSetSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PackSetSet.m; sourceTree = "<group>"; };
|
||||
F8D6782B1160F5D000CC270E /* PackSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PackSet.h; sourceTree = "<group>"; };
|
||||
F8D6782C1160F5D000CC270E /* PackSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PackSet.m; sourceTree = "<group>"; };
|
||||
F8D678311160F62E00CC270E /* ArqUserLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArqUserLibrary.h; sourceTree = "<group>"; };
|
||||
F8D678321160F62E00CC270E /* ArqUserLibrary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArqUserLibrary.m; sourceTree = "<group>"; };
|
||||
F8D6783A1160F70100CC270E /* PackIndexEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PackIndexEntry.h; sourceTree = "<group>"; };
|
||||
F8D6783B1160F70100CC270E /* PackIndexEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PackIndexEntry.m; sourceTree = "<group>"; };
|
||||
F8D678411160F74A00CC270E /* DiskPack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskPack.h; sourceTree = "<group>"; };
|
||||
F8D678421160F74A00CC270E /* DiskPack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiskPack.m; sourceTree = "<group>"; };
|
||||
F8D678431160F74A00CC270E /* DiskPackIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskPackIndex.h; sourceTree = "<group>"; };
|
||||
F8D678441160F74A00CC270E /* DiskPackIndex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiskPackIndex.m; sourceTree = "<group>"; };
|
||||
F8D6785B1160F7CE00CC270E /* Commit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Commit.h; sourceTree = "<group>"; };
|
||||
F8D6785C1160F7CF00CC270E /* Commit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Commit.m; sourceTree = "<group>"; };
|
||||
F8D6785D1160F7CF00CC270E /* Tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tree.h; sourceTree = "<group>"; };
|
||||
F8D6785E1160F7CF00CC270E /* Tree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Tree.m; sourceTree = "<group>"; };
|
||||
F8D678631160F7FE00CC270E /* NSData-Encrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData-Encrypt.h"; sourceTree = "<group>"; };
|
||||
F8D678641160F7FE00CC270E /* NSData-Encrypt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData-Encrypt.m"; sourceTree = "<group>"; };
|
||||
F8D678681160F81100CC270E /* OpenSSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenSSL.h; sourceTree = "<group>"; };
|
||||
F8D678691160F81100CC270E /* OpenSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenSSL.m; sourceTree = "<group>"; };
|
||||
F8D6786D1160F84600CC270E /* DecryptedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DecryptedInputStream.h; sourceTree = "<group>"; };
|
||||
F8D6786E1160F84600CC270E /* DecryptedInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DecryptedInputStream.m; sourceTree = "<group>"; };
|
||||
F8D678721160F85D00CC270E /* CryptInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptInputStream.h; sourceTree = "<group>"; };
|
||||
F8D678731160F85D00CC270E /* CryptInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CryptInputStream.m; sourceTree = "<group>"; };
|
||||
F8D678751160F86E00CC270E /* FileInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileInputStream.h; sourceTree = "<group>"; };
|
||||
F8D678761160F86E00CC270E /* FileInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileInputStream.m; sourceTree = "<group>"; };
|
||||
F8D678781160F8A000CC270E /* DataIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataIO.h; sourceTree = "<group>"; };
|
||||
F8D678791160F8A000CC270E /* DataIO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataIO.m; sourceTree = "<group>"; };
|
||||
F8D6787A1160F8A000CC270E /* DateIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateIO.h; sourceTree = "<group>"; };
|
||||
F8D6787B1160F8A000CC270E /* DateIO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateIO.m; sourceTree = "<group>"; };
|
||||
F8D6787C1160F8A000CC270E /* DoubleIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DoubleIO.h; sourceTree = "<group>"; };
|
||||
F8D6787D1160F8A000CC270E /* DoubleIO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DoubleIO.m; sourceTree = "<group>"; };
|
||||
F8D6787E1160F8A000CC270E /* IntegerIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntegerIO.h; sourceTree = "<group>"; };
|
||||
F8D6787F1160F8A000CC270E /* IntegerIO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IntegerIO.m; sourceTree = "<group>"; };
|
||||
F8D678801160F8A000CC270E /* StringIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringIO.h; sourceTree = "<group>"; };
|
||||
F8D678811160F8A000CC270E /* StringIO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StringIO.m; sourceTree = "<group>"; };
|
||||
F8D678871160F8CD00CC270E /* NSString_extra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSString_extra.h; sourceTree = "<group>"; };
|
||||
F8D678881160F8CD00CC270E /* NSString_extra.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSString_extra.m; sourceTree = "<group>"; };
|
||||
F8D6788A1160F8E500CC270E /* BinarySHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BinarySHA1.h; sourceTree = "<group>"; };
|
||||
F8D6788B1160F8E500CC270E /* BinarySHA1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BinarySHA1.m; sourceTree = "<group>"; };
|
||||
F8D678981160FA2A00CC270E /* NSFileManager_extra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSFileManager_extra.h; sourceTree = "<group>"; };
|
||||
F8D678991160FA2A00CC270E /* NSFileManager_extra.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSFileManager_extra.m; sourceTree = "<group>"; };
|
||||
F8D6789B1160FA3900CC270E /* FileOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileOutputStream.h; sourceTree = "<group>"; };
|
||||
F8D6789C1160FA3900CC270E /* FileOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileOutputStream.m; sourceTree = "<group>"; };
|
||||
F8D6789E1160FA4800CC270E /* FileInputStreamFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileInputStreamFactory.h; sourceTree = "<group>"; };
|
||||
F8D6789F1160FA4800CC270E /* FileInputStreamFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileInputStreamFactory.m; sourceTree = "<group>"; };
|
||||
F8D678A31160FA5F00CC270E /* BooleanIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BooleanIO.h; sourceTree = "<group>"; };
|
||||
F8D678A41160FA5F00CC270E /* BooleanIO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BooleanIO.m; sourceTree = "<group>"; };
|
||||
F8D678A61160FA6A00CC270E /* EncryptedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EncryptedInputStream.h; sourceTree = "<group>"; };
|
||||
F8D678A71160FA6A00CC270E /* EncryptedInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EncryptedInputStream.m; sourceTree = "<group>"; };
|
||||
F8D678AD1160FAD900CC270E /* CommitFailedFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommitFailedFile.h; sourceTree = "<group>"; };
|
||||
F8D678AE1160FAD900CC270E /* CommitFailedFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommitFailedFile.m; sourceTree = "<group>"; };
|
||||
F8D678B61160FB2100CC270E /* Node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Node.h; sourceTree = "<group>"; };
|
||||
F8D678B71160FB2100CC270E /* Node.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Node.m; sourceTree = "<group>"; };
|
||||
F8D67CE91161363A00CC270E /* FileAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileAttributes.h; sourceTree = "<group>"; };
|
||||
F8D67CEA1161363A00CC270E /* FileAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileAttributes.m; sourceTree = "<group>"; };
|
||||
F8D67CF01161366100CC270E /* XAttrSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XAttrSet.h; sourceTree = "<group>"; };
|
||||
F8D67CF11161366100CC270E /* XAttrSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XAttrSet.m; sourceTree = "<group>"; };
|
||||
F8D67D031161384100CC270E /* FileACL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileACL.h; sourceTree = "<group>"; };
|
||||
F8D67D041161384100CC270E /* FileACL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileACL.m; sourceTree = "<group>"; };
|
||||
F8D67D051161384100CC270E /* OSStatusDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSStatusDescription.h; sourceTree = "<group>"; };
|
||||
F8D67D061161384100CC270E /* OSStatusDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OSStatusDescription.m; sourceTree = "<group>"; };
|
||||
F8D67F6E1161443600CC270E /* RestoreNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RestoreNode.h; sourceTree = "<group>"; };
|
||||
F8D67F6F1161443600CC270E /* RestoreNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RestoreNode.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
|
||||
F805B8891160EB39007EC01E /* libcrypto.dylib in Frameworks */,
|
||||
F805B88B1160EB3A007EC01E /* libicucore.dylib in Frameworks */,
|
||||
F805B88F1160EB45007EC01E /* libssl.dylib in Frameworks */,
|
||||
F805B8931160EB4E007EC01E /* SystemConfiguration.framework in Frameworks */,
|
||||
F805B8A11160EBAA007EC01E /* CoreFoundation.framework in Frameworks */,
|
||||
F805B8C21160EC41007EC01E /* Security.framework in Frameworks */,
|
||||
F805B8CE1160ECD7007EC01E /* CoreServices.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
08FB7794FE84155DC02AAC07 /* arq_restore */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
08FB7795FE84155DC02AAC07 /* Source */,
|
||||
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||
);
|
||||
name = arq_restore;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
08FB7795FE84155DC02AAC07 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F805B8671160EA7C007EC01E /* crypto */,
|
||||
F805B7A61160DEF2007EC01E /* shared */,
|
||||
F805B7401160DCFE007EC01E /* plist */,
|
||||
F805B8081160E7A1007EC01E /* io */,
|
||||
F805B7C91160E445007EC01E /* http */,
|
||||
F805B7651160DD60007EC01E /* s3 */,
|
||||
32A70AAB03705E1F00C91783 /* arq_restore_Prefix.pch */,
|
||||
08FB7796FE84155DC02AAC07 /* arq_restore.m */,
|
||||
F8D678311160F62E00CC270E /* ArqUserLibrary.h */,
|
||||
F8D678321160F62E00CC270E /* ArqUserLibrary.m */,
|
||||
F805B54B1160D3E6007EC01E /* ArqRestoreCommand.h */,
|
||||
F805B54C1160D3E6007EC01E /* ArqRestoreCommand.m */,
|
||||
F805B72E1160DBE9007EC01E /* ArqFolder.h */,
|
||||
F805B72F1160DBE9007EC01E /* ArqFolder.m */,
|
||||
F8D6785B1160F7CE00CC270E /* Commit.h */,
|
||||
F8D6785C1160F7CF00CC270E /* Commit.m */,
|
||||
F8D678AD1160FAD900CC270E /* CommitFailedFile.h */,
|
||||
F8D678AE1160FAD900CC270E /* CommitFailedFile.m */,
|
||||
F8D678411160F74A00CC270E /* DiskPack.h */,
|
||||
F8D678421160F74A00CC270E /* DiskPack.m */,
|
||||
F8D678431160F74A00CC270E /* DiskPackIndex.h */,
|
||||
F8D678441160F74A00CC270E /* DiskPackIndex.m */,
|
||||
F805B71F1160D9C2007EC01E /* HSLog.h */,
|
||||
F805B7201160D9C2007EC01E /* HSLog.m */,
|
||||
F8D678B61160FB2100CC270E /* Node.h */,
|
||||
F8D678B71160FB2100CC270E /* Node.m */,
|
||||
F8D6783A1160F70100CC270E /* PackIndexEntry.h */,
|
||||
F8D6783B1160F70100CC270E /* PackIndexEntry.m */,
|
||||
F8D678291160F5D000CC270E /* PackSetSet.h */,
|
||||
F8D6782A1160F5D000CC270E /* PackSetSet.m */,
|
||||
F8D6782B1160F5D000CC270E /* PackSet.h */,
|
||||
F8D6782C1160F5D000CC270E /* PackSet.m */,
|
||||
F8D677FE1160F26A00CC270E /* Restorer.h */,
|
||||
F8D677FF1160F26A00CC270E /* Restorer.m */,
|
||||
F8D67F6E1161443600CC270E /* RestoreNode.h */,
|
||||
F8D67F6F1161443600CC270E /* RestoreNode.m */,
|
||||
F8D678131160F4E300CC270E /* S3Fark.h */,
|
||||
F8D678141160F4E300CC270E /* S3Fark.m */,
|
||||
F8D678151160F4E300CC270E /* S3Repo.h */,
|
||||
F8D678161160F4E300CC270E /* S3Repo.m */,
|
||||
F8D6785D1160F7CF00CC270E /* Tree.h */,
|
||||
F8D6785E1160F7CF00CC270E /* Tree.m */,
|
||||
F8D67CE91161363A00CC270E /* FileAttributes.h */,
|
||||
F8D67CEA1161363A00CC270E /* FileAttributes.m */,
|
||||
F8D67CF01161366100CC270E /* XAttrSet.h */,
|
||||
F8D67CF11161366100CC270E /* XAttrSet.m */,
|
||||
);
|
||||
name = Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
08FB779EFE84155DC02AAC07 /* Foundation.framework */,
|
||||
F805B8921160EB4E007EC01E /* SystemConfiguration.framework */,
|
||||
F805B8981160EB71007EC01E /* Security.framework */,
|
||||
F805B8A01160EBAA007EC01E /* CoreFoundation.framework */,
|
||||
F805B8BB1160EC38007EC01E /* SecurityFoundation.framework */,
|
||||
F805B8C11160EC41007EC01E /* Security.framework */,
|
||||
F805B8C51160EC4E007EC01E /* Cocoa.framework */,
|
||||
F805B8CD1160ECD7007EC01E /* CoreServices.framework */,
|
||||
F805B8881160EB39007EC01E /* libcrypto.dylib */,
|
||||
F805B88A1160EB39007EC01E /* libicucore.dylib */,
|
||||
F805B88E1160EB45007EC01E /* libssl.dylib */,
|
||||
);
|
||||
name = "External Frameworks and Libraries";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8DD76FA10486AA7600D96B5E /* arq_restore */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F805B7401160DCFE007EC01E /* plist */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F805B7411160DCFE007EC01E /* ArrayNode.h */,
|
||||
F805B7421160DCFE007EC01E /* ArrayNode.m */,
|
||||
F805B7431160DCFE007EC01E /* BooleanNode.h */,
|
||||
F805B7441160DCFE007EC01E /* BooleanNode.m */,
|
||||
F805B7451160DCFE007EC01E /* DictNode.h */,
|
||||
F805B7461160DCFE007EC01E /* DictNode.m */,
|
||||
F805B7471160DCFE007EC01E /* IntegerNode.h */,
|
||||
F805B7481160DCFE007EC01E /* IntegerNode.m */,
|
||||
F805B7491160DCFE007EC01E /* PListNode.h */,
|
||||
F805B74A1160DCFE007EC01E /* PListNodeType.h */,
|
||||
F805B74B1160DCFE007EC01E /* RealNode.h */,
|
||||
F805B74C1160DCFE007EC01E /* RealNode.m */,
|
||||
F805B74D1160DCFE007EC01E /* StringNode.h */,
|
||||
F805B74E1160DCFE007EC01E /* StringNode.m */,
|
||||
F805B74F1160DCFE007EC01E /* XMLPListReader.h */,
|
||||
F805B7501160DCFE007EC01E /* XMLPListReader.m */,
|
||||
F805B7511160DCFE007EC01E /* XMLPListWriter.h */,
|
||||
F805B7521160DCFE007EC01E /* XMLPListWriter.m */,
|
||||
);
|
||||
path = plist;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F805B7651160DD60007EC01E /* s3 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F805B7681160DD60007EC01E /* HTTPConnection_S3.h */,
|
||||
F805B7691160DD60007EC01E /* HTTPConnection_S3.m */,
|
||||
F805B76A1160DD60007EC01E /* NSError_S3.h */,
|
||||
F805B76B1160DD60007EC01E /* NSError_S3.m */,
|
||||
F805B76C1160DD60007EC01E /* PathReceiver.h */,
|
||||
F805B76D1160DD60007EC01E /* PathReceiver.m */,
|
||||
F805B76E1160DD60007EC01E /* S3AuthorizationParameters.h */,
|
||||
F805B76F1160DD60007EC01E /* S3AuthorizationParameters.m */,
|
||||
F805B7701160DD60007EC01E /* S3AuthorizationProvider.h */,
|
||||
F805B7711160DD60007EC01E /* S3AuthorizationProvider.m */,
|
||||
F805B7721160DD60007EC01E /* S3Lister.h */,
|
||||
F805B7731160DD60007EC01E /* S3Lister.m */,
|
||||
F805B7741160DD60007EC01E /* S3ObjectMetadata.h */,
|
||||
F805B7751160DD60007EC01E /* S3ObjectMetadata.m */,
|
||||
F805B7761160DD60007EC01E /* S3ObjectReceiver.h */,
|
||||
F805B7771160DD60007EC01E /* S3ObjectReceiver.m */,
|
||||
F805B77A1160DD60007EC01E /* S3Receiver.h */,
|
||||
F805B77B1160DD60007EC01E /* S3Request.h */,
|
||||
F805B77C1160DD60007EC01E /* S3Request.m */,
|
||||
F805B77D1160DD60007EC01E /* S3Service.h */,
|
||||
F805B77E1160DD60007EC01E /* S3Service.m */,
|
||||
F805B77F1160DD60007EC01E /* S3Signature.h */,
|
||||
F805B7801160DD60007EC01E /* S3Signature.m */,
|
||||
);
|
||||
path = s3;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F805B7A61160DEF2007EC01E /* shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8D6788A1160F8E500CC270E /* BinarySHA1.h */,
|
||||
F8D6788B1160F8E500CC270E /* BinarySHA1.m */,
|
||||
F805B7D61160E456007EC01E /* BlobACL.h */,
|
||||
F805B7D71160E456007EC01E /* BlobACL.m */,
|
||||
F805B7B81160E3AF007EC01E /* Blob.h */,
|
||||
F805B7B91160E3AF007EC01E /* Blob.m */,
|
||||
F805B85E1160E9F0007EC01E /* DNS_SDErrors.h */,
|
||||
F805B85F1160E9F0007EC01E /* DNS_SDErrors.m */,
|
||||
F8D67D031161384100CC270E /* FileACL.h */,
|
||||
F8D67D041161384100CC270E /* FileACL.m */,
|
||||
F805B7DE1160E48B007EC01E /* NSErrorCodes.h */,
|
||||
F8D678871160F8CD00CC270E /* NSString_extra.h */,
|
||||
F8D678881160F8CD00CC270E /* NSString_extra.m */,
|
||||
F805B8631160EA15007EC01E /* NSXMLNode_extra.h */,
|
||||
F805B8641160EA15007EC01E /* NSXMLNode_extra.m */,
|
||||
F8D67D051161384100CC270E /* OSStatusDescription.h */,
|
||||
F8D67D061161384100CC270E /* OSStatusDescription.m */,
|
||||
F805B7FC1160E764007EC01E /* RFC822.h */,
|
||||
F805B7FD1160E764007EC01E /* RFC822.m */,
|
||||
F805B7A71160DEF2007EC01E /* RegexKitLite.h */,
|
||||
F805B7A81160DEF2007EC01E /* RegexKitLite.m */,
|
||||
F805B7DF1160E48B007EC01E /* ServerBlob.h */,
|
||||
F805B7E01160E48B007EC01E /* ServerBlob.m */,
|
||||
F8D6763E1160F22800CC270E /* SetNSError.h */,
|
||||
);
|
||||
path = shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F805B7C91160E445007EC01E /* http */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F805B7CA1160E445007EC01E /* HTTP.h */,
|
||||
F805B7CB1160E445007EC01E /* HTTPConnection.h */,
|
||||
F805B7CC1160E445007EC01E /* HTTPConnection.m */,
|
||||
F805B7CD1160E445007EC01E /* HTTPRequest.h */,
|
||||
F805B7CE1160E445007EC01E /* HTTPRequest.m */,
|
||||
F805B7CF1160E445007EC01E /* HTTPResponse.h */,
|
||||
F805B7D01160E445007EC01E /* HTTPResponse.m */,
|
||||
F805B7F91160E73D007EC01E /* RFC2616DateFormatter.h */,
|
||||
F805B7FA1160E73D007EC01E /* RFC2616DateFormatter.m */,
|
||||
);
|
||||
path = http;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F805B8081160E7A1007EC01E /* io */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8D678A31160FA5F00CC270E /* BooleanIO.h */,
|
||||
F8D678A41160FA5F00CC270E /* BooleanIO.m */,
|
||||
F805B8331160E882007EC01E /* BufferedInputStream.h */,
|
||||
F805B8561160E9C9007EC01E /* CFStreamInputStream.h */,
|
||||
F805B8571160E9C9007EC01E /* CFStreamInputStream.m */,
|
||||
F805B8581160E9C9007EC01E /* CFStreamOutputStream.h */,
|
||||
F805B8591160E9C9007EC01E /* CFStreamOutputStream.m */,
|
||||
F805B8511160E9B0007EC01E /* CFStreamPair.h */,
|
||||
F805B8521160E9B0007EC01E /* CFStreamPair.m */,
|
||||
F805B8211160E857007EC01E /* ChunkedInputStream.h */,
|
||||
F805B8221160E857007EC01E /* ChunkedInputStream.m */,
|
||||
F8D678721160F85D00CC270E /* CryptInputStream.h */,
|
||||
F8D678731160F85D00CC270E /* CryptInputStream.m */,
|
||||
F8D678781160F8A000CC270E /* DataIO.h */,
|
||||
F8D678791160F8A000CC270E /* DataIO.m */,
|
||||
F805B86D1160EAC1007EC01E /* DataInputStreamFactory.h */,
|
||||
F805B86E1160EAC1007EC01E /* DataInputStreamFactory.m */,
|
||||
F805B82D1160E86E007EC01E /* DataInputStream.h */,
|
||||
F805B82E1160E86E007EC01E /* DataInputStream.m */,
|
||||
F8D6787A1160F8A000CC270E /* DateIO.h */,
|
||||
F8D6787B1160F8A000CC270E /* DateIO.m */,
|
||||
F8D6786D1160F84600CC270E /* DecryptedInputStream.h */,
|
||||
F8D6786E1160F84600CC270E /* DecryptedInputStream.m */,
|
||||
F8D6787C1160F8A000CC270E /* DoubleIO.h */,
|
||||
F8D6787D1160F8A000CC270E /* DoubleIO.m */,
|
||||
F8D678A61160FA6A00CC270E /* EncryptedInputStream.h */,
|
||||
F8D678A71160FA6A00CC270E /* EncryptedInputStream.m */,
|
||||
F805B8271160E861007EC01E /* FDInputStream.h */,
|
||||
F805B8281160E861007EC01E /* FDInputStream.m */,
|
||||
F805B8291160E861007EC01E /* FDOutputStream.h */,
|
||||
F805B82A1160E861007EC01E /* FDOutputStream.m */,
|
||||
F8D678751160F86E00CC270E /* FileInputStream.h */,
|
||||
F8D678761160F86E00CC270E /* FileInputStream.m */,
|
||||
F8D6789E1160FA4800CC270E /* FileInputStreamFactory.h */,
|
||||
F8D6789F1160FA4800CC270E /* FileInputStreamFactory.m */,
|
||||
F8D6789B1160FA3900CC270E /* FileOutputStream.h */,
|
||||
F8D6789C1160FA3900CC270E /* FileOutputStream.m */,
|
||||
F805B8231160E857007EC01E /* FixedLengthInputStream.h */,
|
||||
F805B8241160E857007EC01E /* FixedLengthInputStream.m */,
|
||||
F805B8661160EA36007EC01E /* InputStreamFactory.h */,
|
||||
F805B8191160E838007EC01E /* InputStreams.h */,
|
||||
F805B81A1160E838007EC01E /* InputStreams.m */,
|
||||
F805B80B1160E7C3007EC01E /* InputStream.h */,
|
||||
F8D6787E1160F8A000CC270E /* IntegerIO.h */,
|
||||
F8D6787F1160F8A000CC270E /* IntegerIO.m */,
|
||||
F805B8391160E8DD007EC01E /* NSData-InputStream.h */,
|
||||
F805B83A1160E8DD007EC01E /* NSData-InputStream.m */,
|
||||
F8D678981160FA2A00CC270E /* NSFileManager_extra.h */,
|
||||
F8D678991160FA2A00CC270E /* NSFileManager_extra.m */,
|
||||
F805B8361160E8A0007EC01E /* OutputStream.h */,
|
||||
F805B83C1160E900007EC01E /* StreamPair.h */,
|
||||
F805B83D1160E900007EC01E /* StreamPairFactory.h */,
|
||||
F805B83E1160E900007EC01E /* StreamPairFactory.m */,
|
||||
F805B8401160E90F007EC01E /* Streams.h */,
|
||||
F805B8411160E90F007EC01E /* Streams.m */,
|
||||
F8D678801160F8A000CC270E /* StringIO.h */,
|
||||
F8D678811160F8A000CC270E /* StringIO.m */,
|
||||
F805B8301160E878007EC01E /* Writer.h */,
|
||||
F805B8311160E878007EC01E /* Writer.m */,
|
||||
);
|
||||
path = io;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F805B8671160EA7C007EC01E /* crypto */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8D6781B1160F4FD00CC270E /* SHA1Hash.h */,
|
||||
F8D6781C1160F4FD00CC270E /* SHA1Hash.m */,
|
||||
F805B8681160EA83007EC01E /* NSData-Base64Extensions.h */,
|
||||
F805B8691160EA83007EC01E /* NSData-Base64Extensions.m */,
|
||||
F8D678631160F7FE00CC270E /* NSData-Encrypt.h */,
|
||||
F8D678641160F7FE00CC270E /* NSData-Encrypt.m */,
|
||||
F8D678681160F81100CC270E /* OpenSSL.h */,
|
||||
F8D678691160F81100CC270E /* OpenSSL.m */,
|
||||
);
|
||||
path = crypto;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8DD76F960486AA7600D96B5E /* arq_restore */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "arq_restore" */;
|
||||
buildPhases = (
|
||||
8DD76F990486AA7600D96B5E /* Sources */,
|
||||
8DD76F9B0486AA7600D96B5E /* Frameworks */,
|
||||
8DD76F9E0486AA7600D96B5E /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = arq_restore;
|
||||
productInstallPath = "$(HOME)/bin";
|
||||
productName = arq_restore;
|
||||
productReference = 8DD76FA10486AA7600D96B5E /* arq_restore */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "arq_restore" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
hasScannedForEncodings = 1;
|
||||
mainGroup = 08FB7794FE84155DC02AAC07 /* arq_restore */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8DD76F960486AA7600D96B5E /* arq_restore */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8DD76F990486AA7600D96B5E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8DD76F9A0486AA7600D96B5E /* arq_restore.m in Sources */,
|
||||
F805B54D1160D3E6007EC01E /* ArqRestoreCommand.m in Sources */,
|
||||
F805B7211160D9C2007EC01E /* HSLog.m in Sources */,
|
||||
F805B7301160DBE9007EC01E /* ArqFolder.m in Sources */,
|
||||
F805B7531160DCFE007EC01E /* ArrayNode.m in Sources */,
|
||||
F805B7541160DCFE007EC01E /* BooleanNode.m in Sources */,
|
||||
F805B7551160DCFE007EC01E /* DictNode.m in Sources */,
|
||||
F805B7561160DCFE007EC01E /* IntegerNode.m in Sources */,
|
||||
F805B7571160DCFE007EC01E /* RealNode.m in Sources */,
|
||||
F805B7581160DCFE007EC01E /* StringNode.m in Sources */,
|
||||
F805B7591160DCFE007EC01E /* XMLPListReader.m in Sources */,
|
||||
F805B75A1160DCFE007EC01E /* XMLPListWriter.m in Sources */,
|
||||
F805B7821160DD60007EC01E /* HTTPConnection_S3.m in Sources */,
|
||||
F805B7831160DD60007EC01E /* NSError_S3.m in Sources */,
|
||||
F805B7841160DD60007EC01E /* PathReceiver.m in Sources */,
|
||||
F805B7851160DD60007EC01E /* S3AuthorizationParameters.m in Sources */,
|
||||
F805B7861160DD60007EC01E /* S3AuthorizationProvider.m in Sources */,
|
||||
F805B7871160DD60007EC01E /* S3Lister.m in Sources */,
|
||||
F805B7881160DD60007EC01E /* S3ObjectMetadata.m in Sources */,
|
||||
F805B7891160DD60007EC01E /* S3ObjectReceiver.m in Sources */,
|
||||
F805B78B1160DD60007EC01E /* S3Request.m in Sources */,
|
||||
F805B78C1160DD60007EC01E /* S3Service.m in Sources */,
|
||||
F805B78D1160DD60007EC01E /* S3Signature.m in Sources */,
|
||||
F805B7A91160DEF2007EC01E /* RegexKitLite.m in Sources */,
|
||||
F805B7BA1160E3AF007EC01E /* Blob.m in Sources */,
|
||||
F805B7D11160E445007EC01E /* HTTPConnection.m in Sources */,
|
||||
F805B7D21160E445007EC01E /* HTTPRequest.m in Sources */,
|
||||
F805B7D31160E445007EC01E /* HTTPResponse.m in Sources */,
|
||||
F805B7D81160E456007EC01E /* BlobACL.m in Sources */,
|
||||
F805B7E11160E48B007EC01E /* ServerBlob.m in Sources */,
|
||||
F805B7FB1160E73D007EC01E /* RFC2616DateFormatter.m in Sources */,
|
||||
F805B7FE1160E764007EC01E /* RFC822.m in Sources */,
|
||||
F805B81B1160E838007EC01E /* InputStreams.m in Sources */,
|
||||
F805B8251160E857007EC01E /* ChunkedInputStream.m in Sources */,
|
||||
F805B8261160E857007EC01E /* FixedLengthInputStream.m in Sources */,
|
||||
F805B82B1160E861007EC01E /* FDInputStream.m in Sources */,
|
||||
F805B82C1160E861007EC01E /* FDOutputStream.m in Sources */,
|
||||
F805B82F1160E86E007EC01E /* DataInputStream.m in Sources */,
|
||||
F805B8321160E878007EC01E /* Writer.m in Sources */,
|
||||
F805B83B1160E8DD007EC01E /* NSData-InputStream.m in Sources */,
|
||||
F805B83F1160E900007EC01E /* StreamPairFactory.m in Sources */,
|
||||
F805B8421160E90F007EC01E /* Streams.m in Sources */,
|
||||
F805B8531160E9B0007EC01E /* CFStreamPair.m in Sources */,
|
||||
F805B85A1160E9C9007EC01E /* CFStreamInputStream.m in Sources */,
|
||||
F805B85B1160E9C9007EC01E /* CFStreamOutputStream.m in Sources */,
|
||||
F805B8601160E9F0007EC01E /* DNS_SDErrors.m in Sources */,
|
||||
F805B8651160EA15007EC01E /* NSXMLNode_extra.m in Sources */,
|
||||
F805B86A1160EA83007EC01E /* NSData-Base64Extensions.m in Sources */,
|
||||
F805B86F1160EAC1007EC01E /* DataInputStreamFactory.m in Sources */,
|
||||
F8D678001160F26A00CC270E /* Restorer.m in Sources */,
|
||||
F8D678171160F4E300CC270E /* S3Fark.m in Sources */,
|
||||
F8D678181160F4E300CC270E /* S3Repo.m in Sources */,
|
||||
F8D6781D1160F4FD00CC270E /* SHA1Hash.m in Sources */,
|
||||
F8D6782D1160F5D000CC270E /* PackSetSet.m in Sources */,
|
||||
F8D6782E1160F5D000CC270E /* PackSet.m in Sources */,
|
||||
F8D678331160F62E00CC270E /* ArqUserLibrary.m in Sources */,
|
||||
F8D6783C1160F70100CC270E /* PackIndexEntry.m in Sources */,
|
||||
F8D678451160F74A00CC270E /* DiskPack.m in Sources */,
|
||||
F8D678461160F74A00CC270E /* DiskPackIndex.m in Sources */,
|
||||
F8D6785F1160F7CF00CC270E /* Commit.m in Sources */,
|
||||
F8D678601160F7CF00CC270E /* Tree.m in Sources */,
|
||||
F8D678651160F7FE00CC270E /* NSData-Encrypt.m in Sources */,
|
||||
F8D6786A1160F81100CC270E /* OpenSSL.m in Sources */,
|
||||
F8D6786F1160F84600CC270E /* DecryptedInputStream.m in Sources */,
|
||||
F8D678741160F85D00CC270E /* CryptInputStream.m in Sources */,
|
||||
F8D678771160F86E00CC270E /* FileInputStream.m in Sources */,
|
||||
F8D678821160F8A000CC270E /* DataIO.m in Sources */,
|
||||
F8D678831160F8A000CC270E /* DateIO.m in Sources */,
|
||||
F8D678841160F8A000CC270E /* DoubleIO.m in Sources */,
|
||||
F8D678851160F8A000CC270E /* IntegerIO.m in Sources */,
|
||||
F8D678861160F8A000CC270E /* StringIO.m in Sources */,
|
||||
F8D678891160F8CD00CC270E /* NSString_extra.m in Sources */,
|
||||
F8D6788C1160F8E500CC270E /* BinarySHA1.m in Sources */,
|
||||
F8D6789A1160FA2A00CC270E /* NSFileManager_extra.m in Sources */,
|
||||
F8D6789D1160FA3900CC270E /* FileOutputStream.m in Sources */,
|
||||
F8D678A01160FA4800CC270E /* FileInputStreamFactory.m in Sources */,
|
||||
F8D678A51160FA5F00CC270E /* BooleanIO.m in Sources */,
|
||||
F8D678A81160FA6A00CC270E /* EncryptedInputStream.m in Sources */,
|
||||
F8D678AF1160FAD900CC270E /* CommitFailedFile.m in Sources */,
|
||||
F8D678B81160FB2100CC270E /* Node.m in Sources */,
|
||||
F8D67CEB1161363A00CC270E /* FileAttributes.m in Sources */,
|
||||
F8D67CF21161366100CC270E /* XAttrSet.m in Sources */,
|
||||
F8D67D071161384100CC270E /* FileACL.m in Sources */,
|
||||
F8D67D081161384100CC270E /* OSStatusDescription.m in Sources */,
|
||||
F8D67F701161443600CC270E /* RestoreNode.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1DEB927508733DD40010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = arq_restore_Prefix.pch;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INSTALL_PATH = /usr/local/bin;
|
||||
PRODUCT_NAME = arq_restore;
|
||||
SDKROOT = macosx10.5;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB927608733DD40010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = arq_restore_Prefix.pch;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INSTALL_PATH = /usr/local/bin;
|
||||
PRODUCT_NAME = arq_restore;
|
||||
SDKROOT = macosx10.5;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1DEB927908733DD40010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.6;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB927A08733DD40010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.6;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "arq_restore" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB927508733DD40010E9CD /* Debug */,
|
||||
1DEB927608733DD40010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "arq_restore" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB927908733DD40010E9CD /* Debug */,
|
||||
1DEB927A08733DD40010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
|
||||
}
|
||||
4
arq_restore_Prefix.pch
Normal file
4
arq_restore_Prefix.pch
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#ifdef __OBJC__
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HSLog.h"
|
||||
#endif
|
||||
8
arq_restore_usage
Normal file
8
arq_restore_usage
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
usage:
|
||||
- set ARQ_ACCESS_KEY and ARQ_SECRET_KEY
|
||||
- arq_restore
|
||||
- /akiaiyuk3n3tme6l4hfa.com.haystacksoftware.arq.eu/1C493DC6-FB2C-4EEC-8356-838DABE3AE2C/3AA39F05-4C47-4CE5-839A-3A28255DD91E path=/Users/stefan
|
||||
- set ARQ_ENCRYPTION_PASSWORD
|
||||
- arq_restore 3AA39F05-4C47-4CE5-839A-3A28255DD91E
|
||||
- restores 'stefan' folder to local directory, unless 'stefan' folder already exists
|
||||
|
||||
28
crypto/NSData-Base64Extensions.h
Normal file
28
crypto/NSData-Base64Extensions.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2006 Dave Dribin (http://www.dribin.org/dave/)
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSData (Base64)
|
||||
|
||||
- (NSString *) encodeBase64;
|
||||
- (NSString *) encodeBase64WithNewlines: (BOOL) encodeWithNewlines;
|
||||
|
||||
@end
|
||||
57
crypto/NSData-Base64Extensions.m
Normal file
57
crypto/NSData-Base64Extensions.m
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2006 Dave Dribin (http://www.dribin.org/dave/)
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "NSData-Base64Extensions.h"
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
@implementation NSData (Base64)
|
||||
|
||||
- (NSString *) encodeBase64;
|
||||
{
|
||||
return [self encodeBase64WithNewlines: YES];
|
||||
}
|
||||
|
||||
- (NSString *) encodeBase64WithNewlines: (BOOL) encodeWithNewlines;
|
||||
{
|
||||
// Create a memory buffer which will contain the Base64 encoded string
|
||||
BIO * mem = BIO_new(BIO_s_mem());
|
||||
|
||||
// Push on a Base64 filter so that writing to the buffer encodes the data
|
||||
BIO * b64 = BIO_new(BIO_f_base64());
|
||||
if (!encodeWithNewlines)
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
mem = BIO_push(b64, mem);
|
||||
|
||||
// Encode all the data
|
||||
BIO_write(mem, [self bytes], [self length]);
|
||||
BIO_flush(mem);
|
||||
|
||||
// Create a new string from the data in the memory buffer
|
||||
char * base64Pointer;
|
||||
long base64Length = BIO_get_mem_data(mem, &base64Pointer);
|
||||
NSString *base64String = [[[NSString alloc] initWithCString:base64Pointer length:base64Length] autorelease];
|
||||
|
||||
// Clean up and go home
|
||||
BIO_free_all(mem);
|
||||
return base64String;
|
||||
}
|
||||
|
||||
@end
|
||||
41
crypto/NSData-Encrypt.h
Normal file
41
crypto/NSData-Encrypt.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define ARQ_DEFAULT_CIPHER_NAME @"aes256"
|
||||
|
||||
@interface NSData (Encrypt)
|
||||
- (NSData *)encryptWithCipher:(NSString *)cipherName key:(NSString *)key error:(NSError **)error;
|
||||
- (NSData *)decryptWithCipher:(NSString *)cipherName key:(NSString *)key error:(NSError **)error;
|
||||
|
||||
@end
|
||||
190
crypto/NSData-Encrypt.m
Normal file
190
crypto/NSData-Encrypt.m
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <openssl/evp.h>
|
||||
|
||||
#import "NSData-Encrypt.h"
|
||||
#import "OpenSSL.h"
|
||||
#import "SetNSError.h"
|
||||
|
||||
@interface Crypter : NSObject {
|
||||
NSData *data;
|
||||
const EVP_CIPHER *cipher;
|
||||
EVP_CIPHER_CTX cipherContext;
|
||||
unsigned char evp_key[EVP_MAX_KEY_LENGTH];
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH];
|
||||
}
|
||||
- (id)initWithCipher:(NSString *)cipherName key:(NSString *)key data:(NSData *)theData error:(NSError **)error;
|
||||
- (NSData *)encrypt:(NSError **)error;
|
||||
- (NSData *)decrypt:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation Crypter
|
||||
- (id)initWithCipher:(NSString *)cipherName key:(NSString *)key data:(NSData *)theData error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
BOOL ret = NO;
|
||||
do {
|
||||
data = [theData retain];
|
||||
if ([data length] > 0) {
|
||||
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if ([keyData length] > EVP_MAX_KEY_LENGTH) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"encryption key must be less than or equal to %d bytes", EVP_MAX_KEY_LENGTH);
|
||||
break;
|
||||
}
|
||||
if (![OpenSSL initializeSSL:error]) {
|
||||
break;
|
||||
}
|
||||
cipher = EVP_get_cipherbyname([cipherName UTF8String]);
|
||||
if (!cipher) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"failed to load %@ cipher: %@", cipherName, [OpenSSL errorMessage]);
|
||||
break;
|
||||
}
|
||||
|
||||
evp_key[0] = 0;
|
||||
EVP_BytesToKey(cipher, EVP_md5(), NULL, [keyData bytes], [keyData length], 1, evp_key, iv);
|
||||
|
||||
EVP_CIPHER_CTX_init(&cipherContext);
|
||||
}
|
||||
ret = YES;
|
||||
} while(0);
|
||||
if (!ret) {
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
if ([data length] > 0) {
|
||||
EVP_CIPHER_CTX_cleanup(&cipherContext);
|
||||
}
|
||||
[data release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSData *)encrypt:(NSError **)error {
|
||||
if ([data length] == 0) {
|
||||
return [NSData data];
|
||||
}
|
||||
|
||||
if (!EVP_EncryptInit(&cipherContext, cipher, evp_key, iv)) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"EVP_EncryptInit: %@", [OpenSSL errorMessage]);
|
||||
return nil;
|
||||
}
|
||||
EVP_CIPHER_CTX_set_key_length(&cipherContext, EVP_MAX_KEY_LENGTH);
|
||||
|
||||
// Need room for data + cipher block size - 1.
|
||||
unsigned char *outbuf = (unsigned char *)calloc([data length] + EVP_CIPHER_CTX_block_size(&cipherContext) - 1, sizeof(unsigned char));
|
||||
|
||||
int outlen;
|
||||
if (!EVP_EncryptUpdate(&cipherContext, outbuf, &outlen, [data bytes], [data length])) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"EVP_EncryptUpdate: %@", [OpenSSL errorMessage]);
|
||||
return nil;
|
||||
}
|
||||
int templen;
|
||||
if (!EVP_EncryptFinal(&cipherContext, outbuf + outlen, &templen)) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"EVP_EncryptFinal: %@", [OpenSSL errorMessage]);
|
||||
return nil;
|
||||
}
|
||||
outlen += templen;
|
||||
NSData *ret = [[[NSData alloc] initWithBytes:outbuf length:outlen] autorelease];
|
||||
free(outbuf);
|
||||
return ret;
|
||||
}
|
||||
- (NSData *)decrypt:(NSError **)error {
|
||||
if ([data length] == 0) {
|
||||
return [NSData data];
|
||||
}
|
||||
|
||||
int inlen = [data length];
|
||||
unsigned char *input = (unsigned char *)[data bytes];
|
||||
|
||||
// Check for 8-byte salt in encrypted data and skip it.
|
||||
if (inlen > 8+8 && strncmp((const char *)input, "Salted__", 8) == 0) {
|
||||
input += 16;
|
||||
inlen -= 16;
|
||||
}
|
||||
|
||||
if (!EVP_DecryptInit(&cipherContext, cipher, evp_key, iv)) {
|
||||
SETNSERROR(@"NSDataDecryptErrorDomain", -1, @"EVP_DecryptInit: %@", [OpenSSL errorMessage]);
|
||||
return nil;
|
||||
}
|
||||
EVP_CIPHER_CTX_set_key_length(&cipherContext, EVP_MAX_KEY_LENGTH);
|
||||
|
||||
// The data buffer passed to EVP_DecryptUpdate() should have sufficient room for
|
||||
// (input_length + cipher_block_size) bytes unless the cipher block size is 1 in which
|
||||
// case input_length bytes is sufficient.
|
||||
unsigned char *outbuf;
|
||||
if(EVP_CIPHER_CTX_block_size(&cipherContext) > 1) {
|
||||
outbuf = (unsigned char *)calloc(inlen + EVP_CIPHER_CTX_block_size(&cipherContext), sizeof(unsigned char));
|
||||
} else {
|
||||
outbuf = (unsigned char *)calloc(inlen, sizeof(unsigned char));
|
||||
}
|
||||
|
||||
int outlen;
|
||||
if (!EVP_DecryptUpdate(&cipherContext, outbuf, &outlen, input, inlen)) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"EVP_DecryptUpdate: %@", [OpenSSL errorMessage]);
|
||||
return nil;
|
||||
}
|
||||
int templen;
|
||||
if (!EVP_DecryptFinal(&cipherContext, outbuf + outlen, &templen)) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"EVP_DecryptFinal: %@", [OpenSSL errorMessage]);
|
||||
return nil;
|
||||
}
|
||||
outlen += templen;
|
||||
NSData *ret = [[[NSData alloc] initWithBytes:outbuf length:outlen] autorelease];
|
||||
free(outbuf);
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSData (Encrypt)
|
||||
- (NSData *)encryptWithCipher:(NSString *)cipherName key:(NSString *)key error:(NSError **)error {
|
||||
NSData *ret = nil;
|
||||
Crypter *crypter = [[Crypter alloc] initWithCipher:cipherName key:key data:self error:error];
|
||||
if (crypter != nil) {
|
||||
ret = [crypter encrypt:error];
|
||||
[crypter release];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (NSData *)decryptWithCipher:(NSString *)cipherName key:(NSString *)key error:(NSError **)error {
|
||||
NSData *ret = nil;
|
||||
Crypter *crypter = [[Crypter alloc] initWithCipher:cipherName key:key data:self error:error];
|
||||
if (crypter != nil) {
|
||||
ret = [crypter decrypt:error];
|
||||
[crypter release];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
||||
43
crypto/OpenSSL.h
Normal file
43
crypto/OpenSSL.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <openssl/ssl.h>
|
||||
|
||||
|
||||
@interface OpenSSL : NSObject {
|
||||
|
||||
}
|
||||
+ (BOOL)initializeSSL:(NSError **)error;
|
||||
+ (SSL_CTX *)context;
|
||||
+ (NSString *)errorMessage;
|
||||
@end
|
||||
76
crypto/OpenSSL.m
Normal file
76
crypto/OpenSSL.m
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <openssl/err.h>
|
||||
#import <openssl/ssl.h>
|
||||
#import "OpenSSL.h"
|
||||
#import "SetNSError.h"
|
||||
|
||||
static BOOL initialized = NO;
|
||||
static SSL_CTX *ctx;
|
||||
|
||||
@implementation OpenSSL
|
||||
+ (BOOL)initializeSSL:(NSError **)error {
|
||||
if (!initialized) {
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
ERR_load_crypto_strings();
|
||||
ctx = SSL_CTX_new(SSLv23_method());
|
||||
if (ctx == NULL) {
|
||||
SETNSERROR(@"SSLErrorDomain", -1, @"SSL_CTX_new: %@", [OpenSSL errorMessage]);
|
||||
return NO;
|
||||
}
|
||||
initialized = YES;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
+ (SSL_CTX *)context {
|
||||
return ctx;
|
||||
}
|
||||
+ (NSString *)errorMessage {
|
||||
NSMutableString *msg = [NSMutableString string];
|
||||
for (;;) {
|
||||
unsigned long err = ERR_get_error();
|
||||
if (err == 0) {
|
||||
break;
|
||||
}
|
||||
if ([msg length] > 0) {
|
||||
[msg appendString:@"; "];
|
||||
}
|
||||
[msg appendFormat:@"%s", ERR_error_string(err, NULL)];
|
||||
}
|
||||
if ([msg length] == 0) {
|
||||
[msg appendString:@"(no error)"];
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
@end
|
||||
45
crypto/SHA1Hash.h
Normal file
45
crypto/SHA1Hash.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "InputStream.h"
|
||||
@class Blob;
|
||||
|
||||
@interface SHA1Hash : NSObject {
|
||||
|
||||
}
|
||||
+ (NSString *)hashData:(NSData *)data;
|
||||
+ (NSString *)hashBlob:(Blob *)blob blobLength:(unsigned long long *)blobLength error:(NSError **)error;
|
||||
+ (NSString *)hashStream:(id <InputStream>)is withlength:(uint64_t)length error:(NSError **)error;
|
||||
+ (NSString *)hashFile:(NSString *)path error:(NSError **)error;
|
||||
@end
|
||||
134
crypto/SHA1Hash.m
Normal file
134
crypto/SHA1Hash.m
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "SHA1Hash.h"
|
||||
#include <openssl/sha.h>
|
||||
#import "FileInputStream.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "Blob.h"
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface SHA1Hash (internal)
|
||||
+ (NSString *)hashStream:(id <InputStream>)is error:(NSError **)error;
|
||||
+ (NSString *)hashStream:(id <InputStream>)is streamLength:(unsigned long long *)streamLength error:(NSError **)error;
|
||||
@end
|
||||
|
||||
static NSString *digest2String(unsigned char *digest) {
|
||||
char *str = (char *)calloc(SHA_DIGEST_LENGTH, 2);
|
||||
for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
|
||||
sprintf(&(str[i*2]), "%02x", digest[i]);
|
||||
}
|
||||
NSString *ret = [[[NSString alloc] initWithCString:str length:SHA_DIGEST_LENGTH*2] autorelease];
|
||||
free(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@implementation SHA1Hash
|
||||
+ (NSString *)hashData:(NSData *)data {
|
||||
SHA_CTX ctx;
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, [data bytes], (unsigned long)[data length]);
|
||||
unsigned char md[SHA_DIGEST_LENGTH];
|
||||
SHA1_Final(md, &ctx);
|
||||
return digest2String(md);
|
||||
}
|
||||
+ (NSString *)hashBlob:(Blob *)blob blobLength:(unsigned long long *)blobLength error:(NSError **)error {
|
||||
id <InputStream> is = [blob newInputStream:self];
|
||||
if (is == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSString *sha1 = [SHA1Hash hashStream:is streamLength:blobLength error:error];
|
||||
[is release];
|
||||
return sha1;
|
||||
}
|
||||
+ (NSString *)hashFile:(NSString *)path error:(NSError **)error {
|
||||
NSDictionary *attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:error];
|
||||
if (attribs == nil) {
|
||||
return NO;
|
||||
}
|
||||
FileInputStream *fis = [[FileInputStream alloc] initWithPath:path length:[[attribs objectForKey:NSFileSize] unsignedLongLongValue]];
|
||||
NSString *sha1 = [SHA1Hash hashStream:fis error:error];
|
||||
[fis release];
|
||||
return sha1;
|
||||
}
|
||||
+ (NSString *)hashStream:(id <BufferedInputStream>)bis withlength:(uint64_t)length error:(NSError **)error {
|
||||
SHA_CTX ctx;
|
||||
SHA1_Init(&ctx);
|
||||
uint64_t received = 0;
|
||||
while (received < length) {
|
||||
uint64_t toRead = length - received;
|
||||
NSUInteger thisLength = 0;
|
||||
unsigned char *buf = [bis readMaximum:toRead length:&thisLength error:error];
|
||||
if (buf == NULL) {
|
||||
return nil;
|
||||
}
|
||||
NSAssert(thisLength > 0, @"expected more than 0 bytes");
|
||||
SHA1_Update(&ctx, buf, (unsigned long)thisLength);
|
||||
received += (uint64_t)thisLength;
|
||||
}
|
||||
unsigned char md[SHA_DIGEST_LENGTH];
|
||||
SHA1_Final(md, &ctx);
|
||||
return digest2String(md);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SHA1Hash (internal)
|
||||
+ (NSString *)hashStream:(id <InputStream>)is error:(NSError **)error {
|
||||
unsigned long long length;
|
||||
return [SHA1Hash hashStream:is streamLength:&length error:error];
|
||||
}
|
||||
+ (NSString *)hashStream:(id <InputStream>)is streamLength:(unsigned long long *)streamLength error:(NSError **)error {
|
||||
SHA_CTX ctx;
|
||||
SHA1_Init(&ctx);
|
||||
*streamLength = 0;
|
||||
for (;;) {
|
||||
NSUInteger length = 0;
|
||||
NSError *myError;
|
||||
unsigned char *buf = [is read:&length error:&myError];
|
||||
if (buf == NULL) {
|
||||
if ([myError code] != ERROR_EOF) {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
break; // EOF.
|
||||
}
|
||||
NSAssert(length > 0, @"expected more than 0 bytes");
|
||||
SHA1_Update(&ctx, buf, (unsigned long)length);
|
||||
*streamLength += (unsigned long long)length;
|
||||
}
|
||||
unsigned char md[SHA_DIGEST_LENGTH];
|
||||
SHA1_Final(md, &ctx);
|
||||
return digest2String(md);
|
||||
}
|
||||
@end
|
||||
44
http/HTTP.h
Normal file
44
http/HTTP.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#define HTTP_1_1 @"1.1"
|
||||
#define HTTP_INTERNAL_SERVER_ERROR (500)
|
||||
#define HTTP_FORBIDDEN (403)
|
||||
#define HTTP_BAD_REQUEST (400)
|
||||
#define HTTP_CONFLICT (409)
|
||||
#define HTTP_REQUESTED_RANGE_NOT_SATISFIABLE (416)
|
||||
#define HTTP_LENGTH_REQUIRED (411)
|
||||
#define HTTP_NOT_FOUND (404)
|
||||
#define HTTP_MOVED_PERMANENTLY (301)
|
||||
#define HTTP_MOVED_TEMPORARILY (307)
|
||||
#define HTTP_SERVICE_NOT_AVAILABLE (503)
|
||||
59
http/HTTPConnection.h
Normal file
59
http/HTTPConnection.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@protocol InputStream;
|
||||
@protocol StreamPair;
|
||||
@class HTTPRequest;
|
||||
@class HTTPResponse;
|
||||
|
||||
@interface HTTPConnection : NSObject {
|
||||
id <StreamPair> streamPair;
|
||||
HTTPRequest *request;
|
||||
HTTPResponse *response;
|
||||
}
|
||||
- (id)initWithHost:(NSString *)theHost useSSL:(BOOL)isUseSSL error:(NSError **)error;
|
||||
- (void)setRequestMethod:(NSString *)theRequestMethod pathInfo:(NSString *)thePathInfo queryString:(NSString *)theQueryString protocol:(NSString *)theProtocol;
|
||||
- (void)setRequestHeader:(NSString *)value forKey:(NSString *)key;
|
||||
- (void)setRequestHostHeader;
|
||||
- (void)setRequestKeepAliveHeader;
|
||||
- (void)setRequestContentDispositionHeader:(NSString *)downloadName;
|
||||
- (void)setRFC822DateRequestHeader;
|
||||
- (BOOL)executeRequest:(NSError **)error;
|
||||
- (int)responseCode;
|
||||
- (NSString *)responseHeaderForKey:(NSString *)key;
|
||||
- (NSString *)responseMimeType;
|
||||
- (NSString *)responseDownloadName;
|
||||
- (id <InputStream>)newResponseBodyStream:(NSError **)error;
|
||||
- (NSData *)slurpResponseBody:(NSError **)error;
|
||||
- (void)setCloseRequested;
|
||||
@end
|
||||
135
http/HTTPConnection.m
Normal file
135
http/HTTPConnection.m
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "HTTPConnection.h"
|
||||
#import "HTTPRequest.h"
|
||||
#import "HTTPResponse.h"
|
||||
#import "StreamPairFactory.h"
|
||||
#import "StreamPair.h"
|
||||
#import "Streams.h"
|
||||
#import "RegexKitLite.h"
|
||||
#import "FDOutputStream.h"
|
||||
#import "FDInputStream.h"
|
||||
|
||||
@implementation HTTPConnection
|
||||
- (id)initWithHost:(NSString *)theHost useSSL:(BOOL)isUseSSL error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
streamPair = [[StreamPairFactory theFactory] newStreamPairToHost:theHost useSSL:isUseSSL error:error];
|
||||
if (streamPair == nil) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
request = [[HTTPRequest alloc] initWithHost:theHost];
|
||||
response = [[HTTPResponse alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[streamPair release];
|
||||
[request release];
|
||||
[response release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)setRequestMethod:(NSString *)theRequestMethod pathInfo:(NSString *)thePathInfo queryString:(NSString *)theQueryString protocol:(NSString *)theProtocol {
|
||||
[request setMethod:theRequestMethod];
|
||||
[request setPathInfo:thePathInfo];
|
||||
[request setQueryString:theQueryString];
|
||||
[request setProtocol:theProtocol];
|
||||
}
|
||||
- (void)setRequestHeader:(NSString *)value forKey:(NSString *)key {
|
||||
[request setHeader:value forKey:key];
|
||||
}
|
||||
- (void)setRequestHostHeader {
|
||||
[request setHostHeader];
|
||||
}
|
||||
- (void)setRequestKeepAliveHeader {
|
||||
[request setKeepAliveHeader];
|
||||
}
|
||||
- (void)setRequestContentDispositionHeader:(NSString *)downloadName {
|
||||
[request setContentDispositionHeader:downloadName];
|
||||
}
|
||||
- (void)setRFC822DateRequestHeader {
|
||||
[request setRFC822DateHeader];
|
||||
}
|
||||
- (BOOL)executeRequest:(NSError **)error {
|
||||
if (![request write:streamPair error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (![response readHead:streamPair requestMethod:[request method] error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if ([[response headerForKey:@"Connection"] isEqualToString:@"Close"]) {
|
||||
HSLogDebug(@"Connection: Close header received; requesting close on %@", streamPair);
|
||||
[streamPair setCloseRequested];
|
||||
}
|
||||
if (![[response protocol] isEqualToString:@"1.1"]) {
|
||||
HSLogDebug(@"protocol %@ HTTP response; requesting close on %@", [response protocol], streamPair);
|
||||
[streamPair setCloseRequested];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (int)responseCode {
|
||||
return [response code];
|
||||
}
|
||||
- (NSString *)responseHeaderForKey:(NSString *)key {
|
||||
return [response headerForKey:key];
|
||||
}
|
||||
- (NSString *)responseMimeType {
|
||||
return [response headerForKey:@"Content-Type"];
|
||||
}
|
||||
- (NSString *)responseDownloadName {
|
||||
NSString *downloadName = nil;
|
||||
NSString *contentDisposition = [response headerForKey:@"Content-Disposition"];
|
||||
if (contentDisposition != nil) {
|
||||
NSRange filenameRange = [contentDisposition rangeOfRegex:@"attachment;filename=(.+)" capture:1];
|
||||
if (filenameRange.location != NSNotFound) {
|
||||
downloadName = [contentDisposition substringWithRange:filenameRange];
|
||||
}
|
||||
}
|
||||
return downloadName;
|
||||
}
|
||||
- (id <InputStream>)newResponseBodyStream:(NSError **)error {
|
||||
return [response newResponseInputStream:streamPair error:error];
|
||||
}
|
||||
- (NSData *)slurpResponseBody:(NSError **)error {
|
||||
id <InputStream> is = [self newResponseBodyStream:error];
|
||||
if (is == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSData *data = [is slurp:error];
|
||||
[is release];
|
||||
return data;
|
||||
}
|
||||
- (void)setCloseRequested {
|
||||
[streamPair setCloseRequested];
|
||||
}
|
||||
@end
|
||||
61
http/HTTPRequest.h
Normal file
61
http/HTTPRequest.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@protocol OutputStream;
|
||||
@class RFC2616DateFormatter;
|
||||
|
||||
@interface HTTPRequest : NSObject {
|
||||
NSString *host;
|
||||
NSString *method;
|
||||
NSString *pathInfo;
|
||||
NSString *queryString;
|
||||
NSString *protocol;
|
||||
NSMutableDictionary *headers;
|
||||
RFC2616DateFormatter *dateFormatter;
|
||||
}
|
||||
@property (copy, readonly) NSString *host;
|
||||
@property (copy) NSString *method;
|
||||
@property (copy) NSString *pathInfo;
|
||||
@property (copy) NSString *queryString;
|
||||
@property (copy) NSString *protocol;
|
||||
|
||||
- (id)initWithHost:(NSString *)host;
|
||||
- (void)setHeader:(NSString *)value forKey:(NSString *)key;
|
||||
- (void)setHostHeader;
|
||||
- (void)setKeepAliveHeader;
|
||||
- (void)setRFC822DateHeader;
|
||||
- (void)setContentDispositionHeader:(NSString *)downloadName;
|
||||
- (NSString *)headerForKey:(NSString *)key;
|
||||
- (NSArray *)allHeaderKeys;
|
||||
- (BOOL)write:(id <OutputStream>)os error:(NSError **)error;
|
||||
@end
|
||||
128
http/HTTPRequest.m
Normal file
128
http/HTTPRequest.m
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "HTTPRequest.h"
|
||||
#import "Writer.h"
|
||||
#import "RFC2616DateFormatter.h"
|
||||
|
||||
#define DEFAULT_HTTP_PORT (80)
|
||||
|
||||
@implementation HTTPRequest
|
||||
@synthesize host, method, pathInfo, queryString, protocol;
|
||||
|
||||
- (id)initWithHost:(NSString *)theHost {
|
||||
if (self = [super init]) {
|
||||
host = [theHost retain];
|
||||
headers = [[NSMutableDictionary alloc] init];
|
||||
dateFormatter = [[RFC2616DateFormatter alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[host release];
|
||||
[method release];
|
||||
[pathInfo release];
|
||||
[queryString release];
|
||||
[protocol release];
|
||||
[headers release];
|
||||
[dateFormatter release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)setHeader:(NSString *)value forKey:(NSString *)key {
|
||||
[headers setValue:value forKey:key];
|
||||
}
|
||||
- (void)setHostHeader {
|
||||
[headers setValue:host forKey:@"Host"];
|
||||
}
|
||||
- (void)setKeepAliveHeader {
|
||||
[headers setValue:@"keep-alive" forKey:@"Connection"];
|
||||
}
|
||||
- (void)setRFC822DateHeader {
|
||||
[headers setValue:[dateFormatter rfc2616StringFromDate:[NSDate date]] forKey:@"Date"];
|
||||
}
|
||||
- (void)setContentDispositionHeader:(NSString *)downloadName {
|
||||
if (downloadName != nil) {
|
||||
NSString *encodedFilename = [NSString stringWithFormat:@"\"%@\"", [downloadName stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\\\""]];
|
||||
NSString *contentDisposition = [NSString stringWithFormat:@"attachment;filename=%@", encodedFilename];
|
||||
[self setHeader:contentDisposition forKey:@"Content-Disposition"];
|
||||
}
|
||||
}
|
||||
- (NSString *)headerForKey:(NSString *)key {
|
||||
return [headers objectForKey:key];
|
||||
}
|
||||
- (NSArray *)allHeaderKeys {
|
||||
return [headers allKeys];
|
||||
}
|
||||
- (BOOL)write:(id <OutputStream>)os error:(NSError **)error {
|
||||
HSLogTrace(@"writing %@", self);
|
||||
Writer *writer = [[Writer alloc] initWithOutputStream:os];
|
||||
BOOL ret = NO;
|
||||
do {
|
||||
if (![writer write:method error:error]
|
||||
|| ![writer write:@" " error:error]
|
||||
|| ![writer write:pathInfo error:error]) {
|
||||
break;
|
||||
}
|
||||
if (queryString != nil) {
|
||||
if (![writer write:queryString error:error]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (![writer write:@" HTTP/" error:error]
|
||||
|| ![writer write:protocol error:error]
|
||||
|| ![writer write:@"\r\n" error:error]) {
|
||||
break;
|
||||
}
|
||||
for (NSString *key in [headers allKeys]) {
|
||||
HSLogTrace(@"header: %@ = %@", key, [headers objectForKey:key]);
|
||||
if (![writer write:key error:error]
|
||||
|| ![writer write:@": " error:error]
|
||||
|| ![writer write:[headers objectForKey:key] error:error]
|
||||
|| ![writer write:@"\r\n" error:error]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (![writer write:@"\r\n" error:error]) {
|
||||
break;
|
||||
}
|
||||
ret = YES;
|
||||
} while(0);
|
||||
[writer release];
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma mark NSObject protocol
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<HTTPRequest: %@ %@%@ HTTP/%@>", method, pathInfo, (queryString != nil ? queryString : @""), protocol];
|
||||
}
|
||||
@end
|
||||
51
http/HTTPResponse.h
Normal file
51
http/HTTPResponse.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@protocol BufferedInputStream;
|
||||
@protocol InputStream;
|
||||
@class FDInputStream;
|
||||
|
||||
@interface HTTPResponse : NSObject {
|
||||
int code;
|
||||
NSString *protocol;
|
||||
NSMutableDictionary *headers;
|
||||
NSString *requestMethod;
|
||||
}
|
||||
- (id)init;
|
||||
- (BOOL)readHead:(id <BufferedInputStream>)is requestMethod:(NSString *)requestMethod error:(NSError **)error;
|
||||
- (int)code;
|
||||
- (NSString *)protocol;
|
||||
- (NSString *)headerForKey:(NSString *)key;
|
||||
- (unsigned long long)contentLength;
|
||||
- (id <InputStream>)newResponseInputStream:(id <BufferedInputStream>)underlyingStream error:(NSError **)error;
|
||||
@end
|
||||
155
http/HTTPResponse.m
Normal file
155
http/HTTPResponse.m
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "HTTPResponse.h"
|
||||
#import "RegexKitLite.h"
|
||||
#import "SetNSError.h"
|
||||
#import "BufferedInputStream.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "ChunkedInputStream.h"
|
||||
#import "FixedLengthInputStream.h"
|
||||
#import "InputStream.h"
|
||||
#import "InputStreams.h"
|
||||
#import "NSData-InputStream.h"
|
||||
#import "FDInputStream.h"
|
||||
|
||||
#define MAX_HTTP_STATUS_LINE_LENGTH (8192)
|
||||
#define MAX_HTTP_HEADER_LINE_LENGTH (8192)
|
||||
|
||||
@implementation HTTPResponse
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
headers = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[requestMethod release];
|
||||
[protocol release];
|
||||
[headers release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (int)code {
|
||||
return code;
|
||||
}
|
||||
- (NSString *)protocol {
|
||||
return protocol;
|
||||
}
|
||||
- (NSString *)headerForKey:(NSString *)key {
|
||||
return [headers objectForKey:key];
|
||||
}
|
||||
- (unsigned long long)contentLength {
|
||||
long long contentLength = 0;
|
||||
NSString *str = [self headerForKey:@"Content-Length"];
|
||||
if (str != nil) {
|
||||
NSScanner *scanner = [NSScanner scannerWithString:str];
|
||||
if (![scanner scanLongLong:&contentLength]) {
|
||||
HSLogWarn(@"unable to scan Content-Length %@", str);
|
||||
}
|
||||
}
|
||||
return (unsigned long long)contentLength;
|
||||
}
|
||||
- (id <InputStream>)newResponseInputStream:(id <BufferedInputStream>)underlyingStream error:(NSError **)error {
|
||||
id <InputStream> ret = nil;
|
||||
if ([requestMethod isEqualToString:@"HEAD"] || code == 204) {
|
||||
ret = [[NSData data] newInputStream];
|
||||
} else {
|
||||
NSString *transferEncoding = [self headerForKey:@"Transfer-Encoding"];
|
||||
NSString *contentLength = [self headerForKey:@"Content-Length"];
|
||||
if (transferEncoding != nil) {
|
||||
if ([[transferEncoding lowercaseString] isEqualToString:@"chunked"]) {
|
||||
ret = [[ChunkedInputStream alloc] initWithUnderlyingStream:underlyingStream];
|
||||
} else {
|
||||
SETNSERROR(@"StreamErrorDomain", -1, @"unknown Transfer-Encoding: %@", transferEncoding);
|
||||
}
|
||||
} else if (contentLength != nil) {
|
||||
int length = [contentLength intValue];
|
||||
ret = [[FixedLengthInputStream alloc] initWithUnderlyingStream:underlyingStream length:(NSUInteger)length];
|
||||
} else {
|
||||
/*
|
||||
* FIXME: handle multipart/byteranges media type.
|
||||
* See rfc2616 section 4.4 ("message length").
|
||||
*/
|
||||
HSLogWarn(@"response body with no content-length");
|
||||
ret = [underlyingStream retain];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)readHead:(id <BufferedInputStream>)inputStream requestMethod:(NSString *)theRequestMethod error:(NSError **)error {
|
||||
[headers removeAllObjects];
|
||||
[requestMethod release];
|
||||
requestMethod = [theRequestMethod copy];
|
||||
NSString *line = [InputStreams readLineWithCRLF:inputStream maxLength:MAX_HTTP_STATUS_LINE_LENGTH error:error];
|
||||
if (line == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSString *pattern = @"^HTTP/(1.\\d)\\s+(\\d+)\\s+(.+)\r\n$";
|
||||
NSRange protoRange = [line rangeOfRegex:pattern capture:1];
|
||||
NSRange codeRange = [line rangeOfRegex:pattern capture:2];
|
||||
if (protoRange.location == NSNotFound || codeRange.location == NSNotFound) {
|
||||
SETNSERROR(@"HTTPResponseErrorDomain", -1, @"unexpected response status line: %@", line);
|
||||
return NO;
|
||||
}
|
||||
protocol = [[line substringWithRange:protoRange] retain];
|
||||
code = [[line substringWithRange:codeRange] intValue];
|
||||
|
||||
NSString *headerPattern = @"^([^:]+):\\s+(.+)\r\n$";
|
||||
for(;;) {
|
||||
line = [InputStreams readLineWithCRLF:inputStream maxLength:MAX_HTTP_HEADER_LINE_LENGTH error:error];
|
||||
if (line == nil) {
|
||||
return NO;
|
||||
}
|
||||
if ([line isEqualToString:@"\r\n"]) {
|
||||
break;
|
||||
}
|
||||
NSRange nameRange = [line rangeOfRegex:headerPattern capture:1];
|
||||
NSRange valueRange = [line rangeOfRegex:headerPattern capture:2];
|
||||
if (nameRange.location == NSNotFound || valueRange.location == NSNotFound) {
|
||||
SETNSERROR(@"HTTPResponseErrorDomain", -1, @"invalid response header: %@", line);
|
||||
return NO;
|
||||
}
|
||||
NSString *name = [line substringWithRange:nameRange];
|
||||
NSString *value = [line substringWithRange:valueRange];
|
||||
if ([headers objectForKey:name] != nil) {
|
||||
HSLogWarn(@"dumping response header %@ = %@", name, [headers objectForKey:name]);
|
||||
}
|
||||
[headers setObject:value forKey:name];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark NSObject protocol
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<HTTPResponse %p: code=%d headers=%@>", self, code, headers];
|
||||
}
|
||||
@end
|
||||
41
http/RFC2616DateFormatter.h
Normal file
41
http/RFC2616DateFormatter.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
@interface RFC2616DateFormatter : NSObject {
|
||||
NSLocale *usLocale;
|
||||
NSDateFormatter *formatter;
|
||||
}
|
||||
- (NSString *)rfc2616StringFromDate:(NSDate *)date;
|
||||
@end
|
||||
60
http/RFC2616DateFormatter.m
Normal file
60
http/RFC2616DateFormatter.m
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "RFC2616DateFormatter.h"
|
||||
|
||||
|
||||
@implementation RFC2616DateFormatter
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss z"];
|
||||
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
|
||||
usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
|
||||
if (usLocale != nil) {
|
||||
[formatter setLocale:usLocale];
|
||||
} else {
|
||||
HSLogWarn(@"no en_US locale installed");
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[formatter release];
|
||||
[usLocale release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSString *)rfc2616StringFromDate:(NSDate *)date {
|
||||
//FIXME: If US locale isn't available, put the English words into the date yourself, according to http://www.ietf.org/rfc/rfc2616.txt
|
||||
return [formatter stringFromDate:date];
|
||||
}
|
||||
@end
|
||||
43
io/BooleanIO.h
Normal file
43
io/BooleanIO.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
#import "OutputStream.h"
|
||||
|
||||
@interface BooleanIO : NSObject {
|
||||
|
||||
}
|
||||
+ (void)write:(BOOL)b to:(NSMutableData *)data;
|
||||
+ (BOOL)write:(BOOL)b to:(id <OutputStream>)os error:(NSError **)error;
|
||||
+ (BOOL)read:(BOOL *)value from:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
@end
|
||||
55
io/BooleanIO.m
Normal file
55
io/BooleanIO.m
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "BooleanIO.h"
|
||||
#import "Streams.h"
|
||||
|
||||
@implementation BooleanIO
|
||||
+ (void)write:(BOOL)b to:(NSMutableData *)data {
|
||||
char c = b ? 1 : 0;
|
||||
[data appendBytes:&c length:1];
|
||||
}
|
||||
+ (BOOL)write:(BOOL)b to:(id <OutputStream>)os error:(NSError **)error {
|
||||
unsigned char c = b ? 1 : 0;
|
||||
return [os write:&c length:1 error:error];
|
||||
|
||||
}
|
||||
+ (BOOL)read:(BOOL *)value from:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
*value = NO;
|
||||
unsigned char *bytes = [is readExactly:1 error:error];
|
||||
if (!bytes) {
|
||||
return NO;
|
||||
}
|
||||
*value = bytes[0] != 0;
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
40
io/BufferedInputStream.h
Normal file
40
io/BufferedInputStream.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "InputStream.h"
|
||||
|
||||
@protocol BufferedInputStream <InputStream>
|
||||
- (unsigned char *)readExactly:(NSUInteger)exactLength error:(NSError **)error;
|
||||
- (unsigned char *)readMaximum:(NSUInteger)maximum length:(NSUInteger *)length error:(NSError **)error;
|
||||
- (uint64_t)bytesReceived;
|
||||
@end
|
||||
42
io/CFStreamInputStream.h
Normal file
42
io/CFStreamInputStream.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface CFStreamInputStream : NSObject <BufferedInputStream> {
|
||||
CFReadStreamRef readStream;
|
||||
BOOL isOpen;
|
||||
uint64_t bytesReceived;
|
||||
}
|
||||
- (id)initWithCFReadStream:(CFReadStreamRef)streamRef;
|
||||
@end
|
||||
156
io/CFStreamInputStream.m
Normal file
156
io/CFStreamInputStream.m
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "CFStreamInputStream.h"
|
||||
#import "InputStreams.h"
|
||||
#import "SetNSError.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "CFStreamPair.h"
|
||||
|
||||
#define MY_BUF_SIZE (4096)
|
||||
#define DEFAULT_READ_TIMEOUT_SECONDS (60)
|
||||
|
||||
@interface CFStreamInputStream (internal)
|
||||
- (BOOL)open:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation CFStreamInputStream
|
||||
- (id)initWithCFReadStream:(CFReadStreamRef)streamRef {
|
||||
if (self = [super init]) {
|
||||
readStream = streamRef;
|
||||
CFRetain(readStream);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
CFRelease(readStream);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark InputStream
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
if (![self open:error]) {
|
||||
return NULL;
|
||||
}
|
||||
unsigned char *ret = [self readMaximum:MY_BUF_SIZE length:length error:error];
|
||||
if (ret != NULL) {
|
||||
bytesReceived += (uint64_t)*length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
if (![self open:error]) {
|
||||
return nil;
|
||||
}
|
||||
return [InputStreams slurp:self error:error];
|
||||
}
|
||||
|
||||
#pragma mark BufferedInputStream
|
||||
- (unsigned char *)readExactly:(NSUInteger)exactLength error:(NSError **)error {
|
||||
if (![self open:error]) {
|
||||
return NULL;
|
||||
}
|
||||
if (exactLength > 2147483648) {
|
||||
SETNSERROR(@"InputStreamErrorDomain", -1, @"absurd length %u requested", exactLength);
|
||||
return NULL;
|
||||
}
|
||||
NSMutableData *data = [NSMutableData dataWithLength:exactLength];
|
||||
unsigned char *dataBuf = [data mutableBytes];
|
||||
NSUInteger total = 0;
|
||||
while (total < exactLength) {
|
||||
NSUInteger maximum = exactLength - total;
|
||||
NSUInteger length;
|
||||
unsigned char *ibuf = [self readMaximum:maximum length:&length error:error];
|
||||
if (ibuf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
NSAssert(length > 0, @"expected more than 0 bytes");
|
||||
memcpy(dataBuf + total, ibuf, length);
|
||||
total += length;
|
||||
}
|
||||
bytesReceived += (uint64_t)exactLength;
|
||||
return dataBuf;
|
||||
}
|
||||
- (unsigned char *)readMaximum:(NSUInteger)maximum length:(NSUInteger *)length error:(NSError **)error {
|
||||
if (![self open:error]) {
|
||||
return NULL;
|
||||
}
|
||||
NSUInteger toRead = (MY_BUF_SIZE > maximum) ? maximum : MY_BUF_SIZE;
|
||||
NSMutableData *data = [NSMutableData dataWithLength:toRead];
|
||||
unsigned char *buf = (unsigned char *)[data mutableBytes];
|
||||
CFIndex index = CFReadStreamRead(readStream, buf, toRead);
|
||||
if (index == -1) {
|
||||
if (error != NULL) {
|
||||
CFErrorRef err = CFReadStreamCopyError(readStream);
|
||||
if (err == NULL) {
|
||||
SETNSERROR(@"CFStreamPairErrorDomain", -1, @"unknown network error");
|
||||
} else {
|
||||
*error = [CFStreamPair NSErrorWithNetworkError:err];
|
||||
CFRelease(err);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (index == 0) {
|
||||
SETNSERROR(@"StreamErrorDomain", ERROR_EOF, @"EOF");
|
||||
return NULL;
|
||||
}
|
||||
*length = (NSUInteger)index;
|
||||
bytesReceived += (uint64_t)index;
|
||||
return buf;
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
- (uint64_t)bytesReceived {
|
||||
return bytesReceived;
|
||||
}
|
||||
@end
|
||||
@implementation CFStreamInputStream (internal)
|
||||
- (BOOL)open:(NSError **)error {
|
||||
if (!isOpen) {
|
||||
if (!CFReadStreamOpen(readStream)) {
|
||||
if (error != NULL) {
|
||||
CFErrorRef err = CFReadStreamCopyError(readStream);
|
||||
if (err == NULL) {
|
||||
SETNSERROR(@"CFStreamPairErrorDomain", -1, @"unknown network error");
|
||||
} else {
|
||||
*error = [CFStreamPair NSErrorWithNetworkError:err];
|
||||
CFRelease(err);
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
isOpen = YES;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
42
io/CFStreamOutputStream.h
Normal file
42
io/CFStreamOutputStream.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "OutputStream.h"
|
||||
|
||||
@interface CFStreamOutputStream : NSObject <OutputStream> {
|
||||
CFWriteStreamRef writeStream;
|
||||
BOOL isOpen;
|
||||
unsigned long long bytesWritten;
|
||||
}
|
||||
- (id)initWithCFWriteStream:(CFWriteStreamRef)streamRef;
|
||||
@end
|
||||
86
io/CFStreamOutputStream.m
Normal file
86
io/CFStreamOutputStream.m
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "CFStreamOutputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "CFStreamPair.h"
|
||||
|
||||
@implementation CFStreamOutputStream
|
||||
- (id)initWithCFWriteStream:(CFWriteStreamRef)streamRef {
|
||||
if (self = [super init]) {
|
||||
writeStream = streamRef;
|
||||
CFRetain(streamRef);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
CFWriteStreamClose(writeStream);
|
||||
CFRelease(writeStream);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark OutputStream
|
||||
- (BOOL)write:(const unsigned char *)buf length:(NSUInteger)len error:(NSError **)error {
|
||||
if (!isOpen) {
|
||||
Boolean ret = CFWriteStreamOpen(writeStream);
|
||||
if (ret == false) {
|
||||
SETNSERROR(@"CFStreamErrorDomain", -1, @"error opening write stream");
|
||||
return NO;
|
||||
}
|
||||
isOpen = YES;
|
||||
}
|
||||
CFIndex index = 0;
|
||||
NSUInteger written = 0;
|
||||
while ((len - written) > 0) {
|
||||
write_again:
|
||||
index = CFWriteStreamWrite(writeStream, &(buf[written]), len - written);
|
||||
if (index == -1) {
|
||||
if (error != NULL) {
|
||||
CFErrorRef err = CFWriteStreamCopyError(writeStream);
|
||||
if (err == NULL) {
|
||||
SETNSERROR(@"CFStreamPairErrorDomain", -1, @"unknown network error");
|
||||
} else {
|
||||
*error = [CFStreamPair NSErrorWithNetworkError:err];
|
||||
CFRelease(err);
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
written += (unsigned long long)index;
|
||||
bytesWritten += (unsigned long long)index;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (unsigned long long)bytesWritten {
|
||||
return bytesWritten;
|
||||
}
|
||||
@end
|
||||
51
io/CFStreamPair.h
Normal file
51
io/CFStreamPair.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "StreamPair.h"
|
||||
@class CFStreamInputStream;
|
||||
@class CFStreamOutputStream;
|
||||
|
||||
@interface CFStreamPair : NSObject <StreamPair> {
|
||||
NSString *description;
|
||||
CFStreamInputStream *is;
|
||||
CFStreamOutputStream *os;
|
||||
NSTimeInterval createTime;
|
||||
NSTimeInterval maxLifetime;
|
||||
BOOL closeRequested;
|
||||
|
||||
}
|
||||
+ (NSString *)errorDomain;
|
||||
+ (NSError *)NSErrorWithNetworkError:(CFErrorRef)err;
|
||||
- (id)initWithHost:(NSString *)theHost useSSL:(BOOL)isUseSSL maxLifetime:(NSTimeInterval)theMaxLifetime;
|
||||
|
||||
@end
|
||||
235
io/CFStreamPair.m
Normal file
235
io/CFStreamPair.m
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#import "CFStreamPair.h"
|
||||
#import "CFStreamInputStream.h"
|
||||
#import "CFStreamOutputStream.h"
|
||||
#import "DNS_SDErrors.h"
|
||||
|
||||
static uint32_t HTTP_PORT = 80;
|
||||
static uint32_t HTTPS_PORT = 443;
|
||||
|
||||
@implementation CFStreamPair
|
||||
+ (NSString *)errorDomain {
|
||||
return @"CFStreamPairErrorDomain";
|
||||
}
|
||||
+ (NSError *)NSErrorWithNetworkError:(CFErrorRef)err {
|
||||
NSString *localizedDescription = @"Network error";
|
||||
NSString *domain = (NSString *)CFErrorGetDomain(err);
|
||||
CFIndex code = CFErrorGetCode(err);
|
||||
CFDictionaryRef userInfo = CFErrorCopyUserInfo(err);
|
||||
if ([domain isEqualToString:(NSString *)kCFErrorDomainCFNetwork]) {
|
||||
if (code == kCFHostErrorHostNotFound) {
|
||||
localizedDescription = @"host not found";
|
||||
} else if (code == kCFHostErrorUnknown) {
|
||||
int gaiCode = 0;
|
||||
if (CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(userInfo, kCFGetAddrInfoFailureKey), kCFNumberIntType, &gaiCode)) {
|
||||
HSLogDebug(@"Host lookup error: %s", gai_strerror(gaiCode));
|
||||
localizedDescription = @"Could not connect to the Internet";
|
||||
}
|
||||
} else if (code == kCFSOCKSErrorUnknownClientVersion) {
|
||||
localizedDescription = @"Unknown SOCKS client version";
|
||||
} else if (code == kCFSOCKSErrorUnsupportedServerVersion) {
|
||||
localizedDescription = [NSString stringWithFormat:@"Unsupported SOCKS server version (server requested version %@)", (NSString *)CFDictionaryGetValue(userInfo, kCFSOCKSVersionKey)];
|
||||
} else if (code == kCFSOCKS4ErrorRequestFailed) {
|
||||
localizedDescription = @"SOCKS4 request rejected or failed";
|
||||
} else if (code == kCFSOCKS4ErrorIdentdFailed) {
|
||||
localizedDescription = @"SOCKS4 server cannot connect to identd on the client";
|
||||
} else if (code == kCFSOCKS4ErrorIdConflict) {
|
||||
localizedDescription = @"SOCKS4 client and identd report different user IDs";
|
||||
} else if (code == kCFSOCKS4ErrorUnknownStatusCode) {
|
||||
localizedDescription = [NSString stringWithFormat:@"SOCKS4 error %@", (NSString *)CFDictionaryGetValue(userInfo, kCFSOCKSStatusCodeKey)];
|
||||
} else if (code == kCFSOCKS5ErrorBadState) {
|
||||
localizedDescription = @"SOCKS5 bad state";
|
||||
} else if (code == kCFSOCKS5ErrorBadResponseAddr) {
|
||||
localizedDescription = @"SOCKS5 bad credentials";
|
||||
} else if (code == kCFSOCKS5ErrorBadCredentials) {
|
||||
localizedDescription = @"SOCKS5 unsupported negotiation method";
|
||||
} else if (code == kCFSOCKS5ErrorUnsupportedNegotiationMethod) {
|
||||
localizedDescription = @"SOCKS5 unsupported negotiation method";
|
||||
} else if (code == kCFSOCKS5ErrorNoAcceptableMethod) {
|
||||
localizedDescription = @"SOCKS5 no acceptable method";
|
||||
} else if (code == kCFNetServiceErrorUnknown) {
|
||||
localizedDescription = @"Unknown Net Services error";
|
||||
} else if (code == kCFNetServiceErrorCollision) {
|
||||
localizedDescription = @"Net Services: collision";
|
||||
} else if (code == kCFNetServiceErrorNotFound) {
|
||||
localizedDescription = @"Net Services: not found";
|
||||
} else if (code == kCFNetServiceErrorInProgress) {
|
||||
localizedDescription = @"Net Services: in progress";
|
||||
} else if (code == kCFNetServiceErrorBadArgument) {
|
||||
localizedDescription = @"Net Services: bad argument";
|
||||
} else if (code == kCFNetServiceErrorCancel) {
|
||||
localizedDescription = @"Net Services: cancelled";
|
||||
} else if (code == kCFNetServiceErrorInvalid) {
|
||||
localizedDescription = @"Net Services: invalid";
|
||||
} else if (code == kCFNetServiceErrorTimeout) {
|
||||
localizedDescription = @"Net Services timeout";
|
||||
} else if (code == kCFNetServiceErrorDNSServiceFailure) {
|
||||
localizedDescription = @"Net Services DNS failure";
|
||||
int dns_sdCode = 0;
|
||||
if (CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(userInfo, kCFDNSServiceFailureKey), kCFNumberIntType, &dns_sdCode)) {
|
||||
localizedDescription = [NSString stringWithFormat:@"Net Services DNS failure: %@", [DNS_SDErrors descriptionForDNS_SDError:dns_sdCode]];
|
||||
}
|
||||
} else if (code == kCFFTPErrorUnexpectedStatusCode) {
|
||||
localizedDescription = [NSString stringWithFormat:@"FTP error %@", (NSString *)CFDictionaryGetValue(userInfo, kCFFTPStatusCodeKey)];
|
||||
} else if (code == kCFErrorHTTPAuthenticationTypeUnsupported) {
|
||||
localizedDescription = @"HTTP authentication type unsupported";
|
||||
} else if (code == kCFErrorHTTPBadCredentials) {
|
||||
localizedDescription = @"bad HTTP credentials";
|
||||
} else if (code == kCFErrorHTTPConnectionLost) {
|
||||
localizedDescription = @"HTTP connection lost";
|
||||
} else if (code == kCFErrorHTTPParseFailure) {
|
||||
localizedDescription = @"HTTP parse failure";
|
||||
} else if (code == kCFErrorHTTPRedirectionLoopDetected) {
|
||||
localizedDescription = @"HTTP redirection loop detected";
|
||||
} else if (code == kCFErrorHTTPBadURL) {
|
||||
localizedDescription = @"bad HTTP URL";
|
||||
} else if (code == kCFErrorHTTPProxyConnectionFailure) {
|
||||
localizedDescription = @"HTTP proxy connection failure";
|
||||
} else if (code == kCFErrorHTTPBadProxyCredentials) {
|
||||
localizedDescription = @"bad HTTP proxy credentials";
|
||||
} else if (code == kCFErrorPACFileError) {
|
||||
localizedDescription = @"HTTP PAC file error";
|
||||
}
|
||||
} else if ([domain isEqualToString:@"NSPOSIXErrorDomain"] && code == ENOTCONN) {
|
||||
localizedDescription = @"Lost connection to the Internet";
|
||||
} else {
|
||||
localizedDescription = [(NSString *)CFErrorCopyDescription(err) autorelease];
|
||||
}
|
||||
CFRelease(userInfo);
|
||||
return [NSError errorWithDomain:[CFStreamPair errorDomain] code:code userInfo:[NSDictionary dictionaryWithObjectsAndKeys:localizedDescription, NSLocalizedDescriptionKey, nil]];
|
||||
}
|
||||
- (id)initWithHost:(NSString *)theHost useSSL:(BOOL)isUseSSL maxLifetime:(NSTimeInterval)theMaxLifetime {
|
||||
if (self = [super init]) {
|
||||
description = [[NSString alloc] initWithFormat:@"<CFStreamPair host=%@ ssl=%@>", theHost, (isUseSSL ? @"YES" : @"NO")];
|
||||
CFReadStreamRef readStream;
|
||||
CFWriteStreamRef writeStream;
|
||||
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef)theHost, (isUseSSL ? HTTPS_PORT : HTTP_PORT), &readStream, &writeStream);
|
||||
if (isUseSSL) {
|
||||
NSDictionary *sslProperties = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamSSLLevel,
|
||||
kCFBooleanTrue, kCFStreamSSLAllowsExpiredCertificates,
|
||||
kCFBooleanTrue, kCFStreamSSLAllowsExpiredRoots,
|
||||
kCFBooleanTrue, kCFStreamSSLAllowsAnyRoot,
|
||||
kCFBooleanFalse, kCFStreamSSLValidatesCertificateChain,
|
||||
kCFNull, kCFStreamSSLPeerName,
|
||||
nil];
|
||||
|
||||
CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, sslProperties);
|
||||
CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, sslProperties);
|
||||
}
|
||||
NSDictionary *proxyDict = (NSDictionary *)SCDynamicStoreCopyProxies(NULL);
|
||||
if ([proxyDict objectForKey:(NSString *)kCFStreamPropertyHTTPProxyHost] != nil) {
|
||||
CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxyDict);
|
||||
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyHTTPProxy, proxyDict);
|
||||
}
|
||||
if ([proxyDict objectForKey:(NSString *)kCFStreamPropertySOCKSProxyHost] != nil && [proxyDict objectForKey:(NSString *)kCFStreamPropertySOCKSProxyPort] != nil) {
|
||||
CFReadStreamSetProperty(readStream, kCFStreamPropertySOCKSProxy, proxyDict);
|
||||
CFWriteStreamSetProperty(writeStream, kCFStreamPropertySOCKSProxy, proxyDict);
|
||||
}
|
||||
[proxyDict release];
|
||||
|
||||
is = [[CFStreamInputStream alloc] initWithCFReadStream:readStream];
|
||||
os = [[CFStreamOutputStream alloc] initWithCFWriteStream:writeStream];
|
||||
CFRelease(readStream);
|
||||
CFRelease(writeStream);
|
||||
createTime = [NSDate timeIntervalSinceReferenceDate];
|
||||
maxLifetime = theMaxLifetime;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[description release];
|
||||
[is release];
|
||||
[os release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)setCloseRequested {
|
||||
closeRequested = YES;
|
||||
}
|
||||
- (BOOL)isUsable {
|
||||
if (closeRequested) {
|
||||
HSLogDebug(@"%@ close requested; not reusing", self);
|
||||
return NO;
|
||||
}
|
||||
if (([NSDate timeIntervalSinceReferenceDate] - createTime) > maxLifetime) {
|
||||
HSLogDebug(@"%@ > %f seconds old; not reusing", self, maxLifetime);
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark BufferedInputStream
|
||||
- (unsigned char *)readExactly:(NSUInteger)exactLength error:(NSError **)error {
|
||||
return [is readExactly:exactLength error:error];
|
||||
}
|
||||
- (unsigned char *)readMaximum:(NSUInteger)maximum length:(NSUInteger *)length error:(NSError **)error {
|
||||
return [is readMaximum:maximum length:length error:error];
|
||||
}
|
||||
- (uint64_t)bytesReceived {
|
||||
return [is bytesReceived];
|
||||
}
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
return [is read:length error:error];
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
return [is slurp:error];
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
|
||||
#pragma mark OutputStream
|
||||
- (BOOL)write:(const unsigned char *)buf length:(NSUInteger)len error:(NSError **)error {
|
||||
NSError *myError = nil;
|
||||
BOOL ret = [os write:buf length:len error:&myError];
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
if (!ret && [[myError domain] isEqualToString:@"UnixErrorDomain"] && [myError code] == EPIPE) {
|
||||
HSLogError(@"broken pipe"); //FIXME: This may not work with CFStream stuff.
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (unsigned long long)bytesWritten {
|
||||
return [os bytesWritten];
|
||||
}
|
||||
|
||||
#pragma mark NSObject
|
||||
- (NSString *)description {
|
||||
return description;
|
||||
}
|
||||
@end
|
||||
43
io/ChunkedInputStream.h
Normal file
43
io/ChunkedInputStream.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "InputStream.h"
|
||||
@class FDInputStream;
|
||||
|
||||
@interface ChunkedInputStream : NSObject <InputStream> {
|
||||
FDInputStream *underlyingStream;
|
||||
NSUInteger chunkLength;
|
||||
NSUInteger received;
|
||||
}
|
||||
- (id)initWithUnderlyingStream:(FDInputStream *)is;
|
||||
@end
|
||||
92
io/ChunkedInputStream.m
Normal file
92
io/ChunkedInputStream.m
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "ChunkedInputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "InputStreams.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "FDInputStream.h"
|
||||
|
||||
#define MAX_CHUNK_LENGTH_LINE_LENGTH (1024)
|
||||
|
||||
@implementation ChunkedInputStream
|
||||
- (id)initWithUnderlyingStream:(FDInputStream *)is {
|
||||
if (self = [super init]) {
|
||||
underlyingStream = [is retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[underlyingStream release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
if (received >= chunkLength) {
|
||||
received = 0;
|
||||
NSString *line = [InputStreams readLineWithCRLF:underlyingStream maxLength:MAX_CHUNK_LENGTH_LINE_LENGTH error:error];
|
||||
if (line == nil) {
|
||||
return NULL;
|
||||
}
|
||||
NSScanner *scanner = [NSScanner scannerWithString:line];
|
||||
if (![scanner scanHexInt:&chunkLength]) {
|
||||
SETNSERROR(@"StreamErrorDomain", -1, @"invalid chunk length: %@", line);
|
||||
return NULL;
|
||||
}
|
||||
HSLogTrace(@"chunk length = %u", chunkLength);
|
||||
}
|
||||
unsigned char *buf = NULL;
|
||||
if (chunkLength == 0) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF (zero chunk length)");
|
||||
} else {
|
||||
buf = [underlyingStream readMaximum:(chunkLength - received) length:length error:error];
|
||||
if (buf) {
|
||||
received += *length;
|
||||
}
|
||||
}
|
||||
if (received >= chunkLength) {
|
||||
NSString *line = [InputStreams readLineWithCRLF:underlyingStream maxLength:MAX_CHUNK_LENGTH_LINE_LENGTH error:error];
|
||||
if (line == nil) {
|
||||
return NULL;
|
||||
}
|
||||
if (![line isEqualToString:@"\r\n"]) {
|
||||
SETNSERROR(@"StreamErrorDomain", -1, @"missing CRLF at end of chunk!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
return [InputStreams slurp:self error:error];
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
@end
|
||||
58
io/CryptInputStream.h
Normal file
58
io/CryptInputStream.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <openssl/evp.h>
|
||||
#import "InputStream.h"
|
||||
|
||||
typedef int (*CryptInitFunc)(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, unsigned char *key, unsigned char *iv);
|
||||
typedef int (*CryptUpdateFunc)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, unsigned char *in, int inl);
|
||||
typedef int (*CryptFinalFunc)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
|
||||
|
||||
@interface CryptInputStream : NSObject <InputStream> {
|
||||
CryptInitFunc cryptInit;
|
||||
CryptUpdateFunc cryptUpdate;
|
||||
CryptFinalFunc cryptFinal;
|
||||
id <InputStream> is;
|
||||
NSUInteger totalInBytesRecvd;
|
||||
unsigned char *outBuf;
|
||||
NSUInteger outBufLen;
|
||||
const EVP_CIPHER *cipher;
|
||||
EVP_CIPHER_CTX cipherContext;
|
||||
unsigned char evp_key[EVP_MAX_KEY_LENGTH];
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH];
|
||||
size_t blockSize;
|
||||
BOOL initialized;
|
||||
BOOL finalized;
|
||||
}
|
||||
- (id)initWithCryptInitFunc:(void *)theCryptInit cryptUpdateFunc:(void *)theCryptUpdate cryptFinalFunc:(void *)theCryptFinal inputStream:(id <InputStream>)theIS cipherName:(NSString *)theCipherName key:(NSString *)theKey error:(NSError **)error;
|
||||
@end
|
||||
187
io/CryptInputStream.m
Normal file
187
io/CryptInputStream.m
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "CryptInputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "OpenSSL.h"
|
||||
#import "InputStreams.h"
|
||||
#import "NSErrorCodes.h"
|
||||
|
||||
@interface CryptInputStream (internal)
|
||||
- (unsigned char *)readAtLeastBlockSize:(NSUInteger *)length error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation CryptInputStream
|
||||
- (id)initWithCryptInitFunc:(void *)theCryptInit cryptUpdateFunc:(void *)theCryptUpdate cryptFinalFunc:(void *)theCryptFinal inputStream:(id <InputStream>)theIS cipherName:(NSString *)theCipherName key:(NSString *)theKey error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
cryptInit = (CryptInitFunc)theCryptInit;
|
||||
cryptUpdate = (CryptUpdateFunc)theCryptUpdate;
|
||||
cryptFinal = (CryptFinalFunc)theCryptFinal;
|
||||
BOOL ret = NO;
|
||||
do {
|
||||
is = [theIS retain];
|
||||
NSData *keyData = [theKey dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if ([keyData length] > EVP_MAX_KEY_LENGTH) {
|
||||
SETNSERROR(@"EncryptedInputStreamErrorDomain", -1, @"encryption key must be less than or equal to %d bytes", EVP_MAX_KEY_LENGTH);
|
||||
break;
|
||||
}
|
||||
if (![OpenSSL initializeSSL:error]) {
|
||||
break;
|
||||
}
|
||||
cipher = EVP_get_cipherbyname([theCipherName UTF8String]);
|
||||
if (!cipher) {
|
||||
SETNSERROR(@"EncryptedInputStreamErrorDomain", -1, @"failed to load %@ cipher: %@", theCipherName, [OpenSSL errorMessage]);
|
||||
break;
|
||||
}
|
||||
evp_key[0] = 0;
|
||||
EVP_BytesToKey(cipher, EVP_md5(), NULL, [keyData bytes], [keyData length], 1, evp_key, iv);
|
||||
EVP_CIPHER_CTX_init(&cipherContext);
|
||||
if (!(*cryptInit)(&cipherContext, cipher, evp_key, iv)) {
|
||||
SETNSERROR(@"NSDataEncryptErrorDomain", -1, @"EVP_EncryptInit: %@", [OpenSSL errorMessage]);
|
||||
break;
|
||||
}
|
||||
EVP_CIPHER_CTX_set_key_length(&cipherContext, EVP_MAX_KEY_LENGTH);
|
||||
blockSize = (unsigned long long)EVP_CIPHER_CTX_block_size(&cipherContext);
|
||||
initialized = YES;
|
||||
ret = YES;
|
||||
} while(0);
|
||||
if (!ret) {
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
if (initialized) {
|
||||
EVP_CIPHER_CTX_cleanup(&cipherContext);
|
||||
}
|
||||
if (outBuf != NULL) {
|
||||
free(outBuf);
|
||||
}
|
||||
[is release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (BOOL)cryptUpdate:(int *)outLen inBuf:(unsigned char *)inBuf inLen:(NSUInteger)inLen {
|
||||
@throw [NSException exceptionWithName:@"PureVirtualMethod" reason:@"don't call this" userInfo:nil];
|
||||
}
|
||||
- (BOOL)cryptFinal:(int *)outLen {
|
||||
@throw [NSException exceptionWithName:@"PureVirtualMethod" reason:@"don't call this" userInfo:nil];
|
||||
}
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
if (finalized) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"already finalized");
|
||||
return NULL;
|
||||
}
|
||||
NSUInteger inLen = 0;
|
||||
int outLen = 0;
|
||||
NSError *myError;
|
||||
unsigned char *inBuf = [self readAtLeastBlockSize:&inLen error:&myError];
|
||||
if (inBuf == NULL && [myError code] != ERROR_EOF) {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
NSUInteger neededBufLen = inLen + blockSize;
|
||||
if (outBufLen < neededBufLen) {
|
||||
if (outBuf == NULL) {
|
||||
outBuf = (unsigned char *)malloc(neededBufLen);
|
||||
} else {
|
||||
outBuf = (unsigned char *)realloc(outBuf, neededBufLen);
|
||||
}
|
||||
outBufLen = neededBufLen;
|
||||
}
|
||||
if (inBuf != NULL) {
|
||||
NSAssert(inLen > 0, @"expected more than 0 input bytes");
|
||||
totalInBytesRecvd += inLen;
|
||||
if (!(*cryptUpdate)(&cipherContext, outBuf, &outLen, inBuf, inLen)) {
|
||||
SETNSERROR(@"OpenSSLErrorDomain", -1, @"crypt update: %@", [OpenSSL errorMessage]);
|
||||
return NULL;
|
||||
}
|
||||
NSAssert(outLen < outBufLen, @"can't receive more bytes than outBufLen from EVP_EncryptUpdate");
|
||||
}
|
||||
if (outLen == 0) {
|
||||
finalized = YES;
|
||||
if (totalInBytesRecvd > 0 && !(*cryptFinal)(&cipherContext, outBuf, &outLen)) {
|
||||
SETNSERROR(@"OpenSSLErrorDomain", -1, @"crypt final: %@", [OpenSSL errorMessage]);
|
||||
return NULL;
|
||||
}
|
||||
NSAssert(outLen < outBufLen, @"can't receive more bytes than outBufLen from EVP_EncryptFinal");
|
||||
}
|
||||
if (outLen == 0) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF on encrypted input stream");
|
||||
return NULL;
|
||||
}
|
||||
NSAssert(outLen > 0, @"outLen must be greater than 0");
|
||||
*length = (NSUInteger)outLen;
|
||||
return outBuf;
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
return [InputStreams slurp:self error:error];
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
|
||||
@end
|
||||
@implementation CryptInputStream (internal)
|
||||
- (unsigned char *)readAtLeastBlockSize:(NSUInteger *)length error:(NSError **)error {
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
while ([data length] < blockSize) {
|
||||
NSUInteger recvd = 0;
|
||||
NSError *myError = nil;
|
||||
unsigned char *buf = [is read:&recvd error:&myError];
|
||||
if (buf == NULL) {
|
||||
if ([myError code] != ERROR_EOF) {
|
||||
if (error != NULL) {
|
||||
*error = myError;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (recvd > blockSize && [data length] == 0) {
|
||||
// Short-circuit to avoid a buffer copy.
|
||||
*length = recvd;
|
||||
return buf;
|
||||
}
|
||||
[data appendBytes:buf length:recvd];
|
||||
}
|
||||
if ([data length] == 0) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF");
|
||||
return NULL;
|
||||
}
|
||||
NSAssert([data length] > 0, @"must have received some bytes");
|
||||
*length = [data length];
|
||||
return [data mutableBytes];
|
||||
}
|
||||
@end
|
||||
42
io/DataIO.h
Normal file
42
io/DataIO.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface DataIO : NSObject {
|
||||
|
||||
}
|
||||
+ (void)write:(NSData *)data to:(NSMutableData *)data;
|
||||
+ (BOOL)read:(NSData **)value from:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
|
||||
@end
|
||||
56
io/DataIO.m
Normal file
56
io/DataIO.m
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "DataIO.h"
|
||||
#import "IntegerIO.h"
|
||||
#import "Streams.h"
|
||||
|
||||
@implementation DataIO
|
||||
+ (void)write:(NSData *)data to:(NSMutableData *)outData {
|
||||
[IntegerIO writeUInt64:(uint64_t)[data length] to:outData];
|
||||
[outData appendBytes:[data bytes] length:[data length]];
|
||||
}
|
||||
+ (BOOL)read:(NSData **)value from:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
*value = NO;
|
||||
uint64_t length = 0;
|
||||
if (![IntegerIO readUInt64:&length from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
unsigned char *bytes = [is readExactly:length error:error];
|
||||
if (!bytes) {
|
||||
return NO;
|
||||
}
|
||||
*value = [NSData dataWithBytes:bytes length:length];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
42
io/DataInputStream.h
Normal file
42
io/DataInputStream.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface DataInputStream : NSObject <BufferedInputStream> {
|
||||
NSData *data;
|
||||
NSUInteger pos;
|
||||
}
|
||||
- (id)initWithData:(NSData *)theData;
|
||||
- (id)initWithData:(NSData *)theData offset:(unsigned long long)theOffset length:(unsigned long long)theLength;
|
||||
@end
|
||||
112
io/DataInputStream.m
Normal file
112
io/DataInputStream.m
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "DataInputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "NSErrorCodes.h"
|
||||
|
||||
@implementation DataInputStream
|
||||
- (id)initWithData:(NSData *)theData {
|
||||
if (self = [super init]) {
|
||||
data = [theData retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (id)initWithData:(NSData *)theData offset:(unsigned long long)theOffset length:(unsigned long long)theLength {
|
||||
if (self = [super init]) {
|
||||
data = [theData subdataWithRange:NSMakeRange((NSUInteger)theOffset, (NSUInteger)theLength)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[data release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark InputStream protocol
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
if (pos >= [data length]) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF on data");
|
||||
return NULL;
|
||||
}
|
||||
NSUInteger remaining = [data length] - pos;
|
||||
*length = remaining;
|
||||
unsigned char *ret = (unsigned char *)[data bytes] + pos;
|
||||
pos = [data length];
|
||||
return ret;
|
||||
}
|
||||
- (unsigned char *)readMaximum:(NSUInteger)maximum length:(NSUInteger *)length error:(NSError **)error {
|
||||
if (pos >= [data length]) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF on data");
|
||||
return NULL;
|
||||
}
|
||||
NSUInteger len = [data length] - pos;
|
||||
if (len > maximum) {
|
||||
len = maximum;
|
||||
}
|
||||
unsigned char *buf = (unsigned char *)[data bytes] + pos;
|
||||
pos += len;
|
||||
return buf;
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
if (pos == 0) {
|
||||
/* This is both a short-circuit and a hack.
|
||||
* The short-circuit part is avoiding copying 'data'.
|
||||
* The hack part is if [data length] == 0, we return the empty 'data' instead of an EOF error.
|
||||
*/
|
||||
return [[data retain] autorelease];
|
||||
}
|
||||
if (pos >= [data length]) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF on data");
|
||||
return NULL;
|
||||
}
|
||||
NSData *ret = [data subdataWithRange:NSMakeRange(pos, [data length] - pos)];
|
||||
pos = [data length];
|
||||
return ret;
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
- (uint64_t)bytesReceived {
|
||||
return (uint64_t)pos;
|
||||
}
|
||||
|
||||
#pragma mark BufferedInputStream protocol
|
||||
- (unsigned char *)readExactly:(NSUInteger)exactLength error:(NSError **)error {
|
||||
if (([data length] - pos) < exactLength) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF");
|
||||
return NULL;
|
||||
}
|
||||
unsigned char *buf = (unsigned char *)[data bytes] + pos;
|
||||
pos += exactLength;
|
||||
return buf;
|
||||
}
|
||||
@end
|
||||
40
io/DataInputStreamFactory.h
Normal file
40
io/DataInputStreamFactory.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "InputStreamFactory.h"
|
||||
|
||||
@interface DataInputStreamFactory : NSObject <InputStreamFactory> {
|
||||
NSData *data;
|
||||
}
|
||||
- (id)initWithData:(NSData *)theData;
|
||||
@end
|
||||
56
io/DataInputStreamFactory.m
Normal file
56
io/DataInputStreamFactory.m
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "DataInputStreamFactory.h"
|
||||
#import "DataInputStream.h"
|
||||
#import "NSData-InputStream.h"
|
||||
|
||||
@implementation DataInputStreamFactory
|
||||
- (id)initWithData:(NSData *)theData {
|
||||
if (self = [super init]) {
|
||||
data = [theData retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[data release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark InputStreamFactory protocol
|
||||
- (id <InputStream>) newInputStream:(id)sender {
|
||||
return [data newInputStream];
|
||||
}
|
||||
- (id <InputStream>) newInputStream:(id)sender sourceOffset:(unsigned long long)theOffset sourceLength:(unsigned long long)theLength {
|
||||
return [[DataInputStream alloc] initWithData:data offset:theOffset length:theLength];
|
||||
}
|
||||
@end
|
||||
41
io/DateIO.h
Normal file
41
io/DateIO.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface DateIO : NSObject {
|
||||
|
||||
}
|
||||
+ (void)write:(NSDate *)date to:(NSMutableData *)data;
|
||||
+ (BOOL)read:(NSDate **)date from:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
@end
|
||||
61
io/DateIO.m
Normal file
61
io/DateIO.m
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "BooleanIO.h"
|
||||
#import "IntegerIO.h"
|
||||
#import "DateIO.h"
|
||||
|
||||
@implementation DateIO
|
||||
+ (void)write:(NSDate *)date to:(NSMutableData *)data {
|
||||
BOOL dateNotNil = (date != nil);
|
||||
[BooleanIO write:dateNotNil to:data];
|
||||
if (dateNotNil) {
|
||||
long long millisecondsSince1970 = (long long)([date timeIntervalSince1970] * 1000.0);
|
||||
[IntegerIO writeInt64:millisecondsSince1970 to:data];
|
||||
}
|
||||
}
|
||||
+ (BOOL)read:(NSDate **)date from:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
*date = nil;
|
||||
BOOL notNil;
|
||||
if (![BooleanIO read:¬Nil from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (notNil) {
|
||||
long long millisecondsSince1970;
|
||||
if (![IntegerIO readInt64:&millisecondsSince1970 from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
*date = [NSDate dateWithTimeIntervalSince1970:((double)millisecondsSince1970 / 1000.0)];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
39
io/DecryptedInputStream.h
Normal file
39
io/DecryptedInputStream.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "CryptInputStream.h"
|
||||
|
||||
@interface DecryptedInputStream : CryptInputStream {
|
||||
}
|
||||
- (id)initWithInputStream:(id <InputStream>)theIS cipherName:(NSString *)theCipherName key:(NSString *)theKey error:(NSError **)error;
|
||||
@end
|
||||
41
io/DecryptedInputStream.m
Normal file
41
io/DecryptedInputStream.m
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "DecryptedInputStream.h"
|
||||
#include <openssl/evp.h>
|
||||
|
||||
@implementation DecryptedInputStream
|
||||
- (id)initWithInputStream:(id <InputStream>)theIS cipherName:(NSString *)theCipherName key:(NSString *)theKey error:(NSError **)error {
|
||||
self = [super initWithCryptInitFunc:&EVP_DecryptInit cryptUpdateFunc:&EVP_DecryptUpdate cryptFinalFunc:&EVP_DecryptFinal inputStream:theIS cipherName:theCipherName key:theKey error:error];
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
41
io/DoubleIO.h
Normal file
41
io/DoubleIO.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface DoubleIO : NSObject {
|
||||
|
||||
}
|
||||
+ (void)write:(double)d to:(NSMutableData *)data;
|
||||
+ (BOOL)read:(double *)value from:(id <BufferedInputStream>)is error:(NSError **)error;
|
||||
@end
|
||||
65
io/DoubleIO.m
Normal file
65
io/DoubleIO.m
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "DoubleIO.h"
|
||||
#import "StringIO.h"
|
||||
#import "SetNSError.h"
|
||||
|
||||
|
||||
//FIXME: Delete this class? It's not used anywhere.
|
||||
|
||||
|
||||
@implementation DoubleIO
|
||||
+ (void)write:(double)d to:(NSMutableData *)data {
|
||||
NSString *str = [NSString stringWithFormat:@"%f", d];
|
||||
[StringIO write:str to:data];
|
||||
}
|
||||
+ (BOOL)read:(double *)value from:(id <BufferedInputStream>)is error:(NSError **)error {
|
||||
if (error) {
|
||||
*error = 0;
|
||||
}
|
||||
*value = 0;
|
||||
NSString *str;
|
||||
if (![StringIO read:&str from:is error:error]) {
|
||||
return NO;
|
||||
}
|
||||
if (!str) {
|
||||
SETNSERROR(@"DoubleIOErrorDomain", -1, @"nil string; expected a double");
|
||||
return NO;
|
||||
}
|
||||
BOOL ret = [[NSScanner scannerWithString:str] scanDouble:value];
|
||||
if (!ret) {
|
||||
SETNSERROR(@"DoubleIOErrorDomain", -1, @"%@ does not contain a double", str);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
39
io/EncryptedInputStream.h
Normal file
39
io/EncryptedInputStream.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "CryptInputStream.h"
|
||||
|
||||
@interface EncryptedInputStream : CryptInputStream {
|
||||
}
|
||||
- (id)initWithInputStream:(id <InputStream>)theIS cipherName:(NSString *)theCipherName key:(NSString *)theKey error:(NSError **)error;
|
||||
@end
|
||||
41
io/EncryptedInputStream.m
Normal file
41
io/EncryptedInputStream.m
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "EncryptedInputStream.h"
|
||||
#import <openssl/evp.h>
|
||||
|
||||
@implementation EncryptedInputStream
|
||||
- (id)initWithInputStream:(id <InputStream>)theIS cipherName:(NSString *)theCipherName key:(NSString *)theKey error:(NSError **)error {
|
||||
self = [super initWithCryptInitFunc:&EVP_EncryptInit cryptUpdateFunc:&EVP_EncryptUpdate cryptFinalFunc:&EVP_EncryptFinal inputStream:theIS cipherName:theCipherName key:theKey error:error];
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
42
io/FDInputStream.h
Normal file
42
io/FDInputStream.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface FDInputStream : NSObject <BufferedInputStream> {
|
||||
int fd;
|
||||
uint64_t bytesReceived;
|
||||
}
|
||||
+ (void)setReadTimeoutSeconds:(time_t)timeout;
|
||||
- (id)initWithFD:(int)theFD;
|
||||
@end
|
||||
141
io/FDInputStream.m
Normal file
141
io/FDInputStream.m
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "FDInputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "InputStreams.h"
|
||||
#import "NSErrorCodes.h"
|
||||
|
||||
#define MY_BUF_SIZE (4096)
|
||||
#define DEFAULT_READ_TIMEOUT_SECONDS (60)
|
||||
|
||||
static time_t readTimeoutSeconds = DEFAULT_READ_TIMEOUT_SECONDS;
|
||||
|
||||
@implementation FDInputStream
|
||||
+ (void)setReadTimeoutSeconds:(time_t)timeout {
|
||||
readTimeoutSeconds = timeout;
|
||||
HSLogInfo(@"network read timeout set to %d seconds", timeout);
|
||||
}
|
||||
- (id)initWithFD:(int)theFD {
|
||||
if (self = [super init]) {
|
||||
fd = theFD;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
}
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
return [self readMaximum:MY_BUF_SIZE length:length error:error];
|
||||
}
|
||||
- (unsigned char *)readMaximum:(NSUInteger)maximum length:(NSUInteger *)length error:(NSError **)error {
|
||||
NSUInteger toRead = (MY_BUF_SIZE > maximum) ? maximum : MY_BUF_SIZE;
|
||||
NSMutableData *data = [NSMutableData dataWithLength:toRead];
|
||||
unsigned char *buf = (unsigned char *)[data mutableBytes];
|
||||
int ret = 0;
|
||||
fd_set readSet;
|
||||
fd_set exceptSet;
|
||||
FD_ZERO(&readSet);
|
||||
FD_SET((unsigned int)fd, &readSet);
|
||||
FD_ZERO(&exceptSet);
|
||||
FD_SET((unsigned int)fd, &exceptSet);
|
||||
struct timeval timeout;
|
||||
struct timeval *pTimeout;
|
||||
|
||||
select_again:
|
||||
timeout.tv_sec = readTimeoutSeconds;
|
||||
timeout.tv_usec = 0;
|
||||
pTimeout = (readTimeoutSeconds > 0) ? &timeout : 0;
|
||||
ret = select(fd + 1, &readSet, 0, &exceptSet, pTimeout);
|
||||
if ((ret == -1) && (errno == EINTR)) {
|
||||
goto select_again;
|
||||
} else if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"select: %s", strerror(errno));
|
||||
return NULL;
|
||||
} else if (ret == 0) {
|
||||
SETNSERROR(@"InputStreamErrorDomain", -1, @"read timeout");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read_again:
|
||||
ret = read(fd, buf, toRead);
|
||||
if ((ret == -1) && (errno == EINTR)) {
|
||||
goto read_again;
|
||||
} else if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"read: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (ret == 0) {
|
||||
SETNSERROR(@"StreamErrorDomain", ERROR_EOF, @"EOF on fd %d", fd);
|
||||
return NULL;
|
||||
}
|
||||
*length = (NSUInteger)ret;
|
||||
bytesReceived += (uint64_t)ret;
|
||||
return buf;
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
return [InputStreams slurp:self error:error];
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
|
||||
#pragma mark BufferedInputStream protocol
|
||||
- (unsigned char *)readExactly:(NSUInteger)exactLength error:(NSError **)error {
|
||||
if (exactLength > 2147483648) {
|
||||
SETNSERROR(@"InputStreamErrorDomain", -1, @"absurd length %u requested", exactLength);
|
||||
return NULL;
|
||||
}
|
||||
NSMutableData *data = [NSMutableData dataWithLength:exactLength];
|
||||
unsigned char *dataBuf = [data mutableBytes];
|
||||
NSUInteger total = 0;
|
||||
while (total < exactLength) {
|
||||
NSUInteger maximum = exactLength - total;
|
||||
NSUInteger length;
|
||||
unsigned char *ibuf = [self readMaximum:maximum length:&length error:error];
|
||||
if (ibuf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
NSAssert(length > 0, @"expected more than 0 bytes");
|
||||
memcpy(dataBuf + total, ibuf, length);
|
||||
total += length;
|
||||
}
|
||||
bytesReceived += (uint64_t)exactLength;
|
||||
return dataBuf;
|
||||
}
|
||||
- (uint64_t)bytesReceived {
|
||||
return bytesReceived;
|
||||
}
|
||||
#pragma mark NSObject protocol
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<FDInputStream: fd=%d>", fd];
|
||||
}
|
||||
@end
|
||||
42
io/FDOutputStream.h
Normal file
42
io/FDOutputStream.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "OutputStream.h"
|
||||
|
||||
@interface FDOutputStream : NSObject <OutputStream> {
|
||||
int fd;
|
||||
unsigned long long bytesWritten;
|
||||
}
|
||||
- (id)initWithFD:(int)theFD;
|
||||
|
||||
@end
|
||||
64
io/FDOutputStream.m
Normal file
64
io/FDOutputStream.m
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "FDOutputStream.h"
|
||||
#import "SetNSError.h"
|
||||
|
||||
@implementation FDOutputStream
|
||||
- (id)initWithFD:(int)theFD {
|
||||
if (self = [super init]) {
|
||||
fd = theFD;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (BOOL)write:(const unsigned char *)buf length:(NSUInteger)len error:(NSError **)error {
|
||||
int ret = 0;
|
||||
NSUInteger written = 0;
|
||||
while ((len - written) > 0) {
|
||||
write_again:
|
||||
ret = write(fd, &(buf[written]), len - written);
|
||||
if ((ret == -1) && (errno == EINTR)) {
|
||||
goto write_again;
|
||||
}
|
||||
if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"write: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
written += (NSUInteger)ret;
|
||||
bytesWritten += (NSUInteger)ret;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (unsigned long long)bytesWritten {
|
||||
return bytesWritten;
|
||||
}
|
||||
@end
|
||||
46
io/FileInputStream.h
Normal file
46
io/FileInputStream.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "BufferedInputStream.h"
|
||||
|
||||
@interface FileInputStream : NSObject <BufferedInputStream> {
|
||||
int fd;
|
||||
NSString *path;
|
||||
unsigned long long fileLength;
|
||||
unsigned long long offset;
|
||||
unsigned char *buf;
|
||||
uint64_t bytesReceived;
|
||||
}
|
||||
- (id)initWithPath:(NSString *)thePath length:(unsigned long long)theLength;
|
||||
- (id)initWithPath:(NSString *)thePath offset:(unsigned long long)theOffset length:(unsigned long long)theLength;
|
||||
@end
|
||||
162
io/FileInputStream.m
Normal file
162
io/FileInputStream.m
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "FileInputStream.h"
|
||||
#import "SetNSError.h"
|
||||
#import "InputStreams.h"
|
||||
#import "NSErrorCodes.h"
|
||||
|
||||
#define MY_BUF_SIZE (4096)
|
||||
|
||||
@interface FileInputStream (internal)
|
||||
- (void)close;
|
||||
@end
|
||||
|
||||
@implementation FileInputStream
|
||||
- (id)initWithPath:(NSString *)thePath length:(unsigned long long)theLength {
|
||||
if (self = [super init]) {
|
||||
fd = -1;
|
||||
path = [thePath retain];
|
||||
fileLength = theLength;
|
||||
buf = (unsigned char *)malloc(MY_BUF_SIZE);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (id)initWithPath:(NSString *)thePath offset:(unsigned long long)theOffset length:(unsigned long long)theLength {
|
||||
if (self = [super init]) {
|
||||
fd = -1;
|
||||
path = [thePath retain];
|
||||
fileLength = theOffset + theLength;
|
||||
buf = (unsigned char *)malloc(MY_BUF_SIZE);
|
||||
offset = theOffset;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[self close];
|
||||
[path release];
|
||||
free(buf);
|
||||
[super dealloc];
|
||||
}
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
return [self readMaximum:MY_BUF_SIZE length:length error:error];
|
||||
}
|
||||
- (unsigned char *)readMaximum:(NSUInteger)maximum length:(NSUInteger *)length error:(NSError **)error {
|
||||
if (fd == -1) {
|
||||
fd = open([path fileSystemRepresentation], O_RDONLY|O_NOFOLLOW);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
HSLogTrace(@"opened fd %d (%@)", fd, path);
|
||||
if (offset > 0) {
|
||||
if (lseek(fd, (off_t)offset, SEEK_SET) == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"lseek(%@, %qu): %s", path, offset, strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
int ret;
|
||||
unsigned long long remaining = fileLength - offset;
|
||||
unsigned long long toRead = (maximum > remaining) ? remaining : maximum;
|
||||
if (toRead > MY_BUF_SIZE) {
|
||||
toRead = MY_BUF_SIZE;
|
||||
}
|
||||
if (toRead == 0) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"reached EOF");
|
||||
return NULL;
|
||||
}
|
||||
read_again:
|
||||
ret = read(fd, buf, (size_t)toRead);
|
||||
if ((ret == -1) && (errno == EINTR)) {
|
||||
goto read_again;
|
||||
}
|
||||
if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"read: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (ret == 0) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF on %@", path);
|
||||
return NULL;
|
||||
}
|
||||
offset += (unsigned long long)ret;
|
||||
*length = (NSUInteger)ret;
|
||||
bytesReceived += (uint64_t)ret;
|
||||
return buf;
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
return [InputStreams slurp:self error:error];
|
||||
}
|
||||
|
||||
#pragma mark BufferedInputStream
|
||||
- (unsigned char *)readExactly:(NSUInteger)exactLength error:(NSError **)error {
|
||||
if (exactLength > 2147483648) {
|
||||
SETNSERROR(@"InputStreamErrorDomain", -1, @"absurd length %u requested", exactLength);
|
||||
return NULL;
|
||||
}
|
||||
NSMutableData *data = [NSMutableData dataWithLength:exactLength];
|
||||
unsigned char *dataBuf = [data mutableBytes];
|
||||
NSUInteger total = 0;
|
||||
while (total < exactLength) {
|
||||
NSUInteger maximum = exactLength - total;
|
||||
NSUInteger length;
|
||||
unsigned char *ibuf = [self readMaximum:maximum length:&length error:error];
|
||||
if (ibuf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
NSAssert(length > 0, @"expected more than 0 bytes");
|
||||
memcpy(dataBuf + total, ibuf, length);
|
||||
total += length;
|
||||
}
|
||||
return dataBuf;
|
||||
}
|
||||
- (uint64_t)bytesReceived {
|
||||
return bytesReceived;
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
|
||||
#pragma mark NSObject protocol
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<FileInputStream: fd=%d path=%@>", fd, path];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FileInputStream (internal)
|
||||
- (void)close {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
HSLogTrace(@"closed fd %d (%@)", fd, path);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
@end
|
||||
41
io/FileInputStreamFactory.h
Normal file
41
io/FileInputStreamFactory.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "InputStreamFactory.h"
|
||||
|
||||
@interface FileInputStreamFactory : NSObject <InputStreamFactory> {
|
||||
NSString *path;
|
||||
unsigned long long length;
|
||||
}
|
||||
- (id)initWithPath:(NSString *)thePath error:(NSError **)error;
|
||||
@end
|
||||
58
io/FileInputStreamFactory.m
Normal file
58
io/FileInputStreamFactory.m
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "FileInputStreamFactory.h"
|
||||
#import "FileInputStream.h"
|
||||
|
||||
@implementation FileInputStreamFactory
|
||||
- (id)initWithPath:(NSString *)thePath error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
path = [thePath copy];
|
||||
NSDictionary *attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:error];
|
||||
if (attribs == nil) {
|
||||
return nil;
|
||||
}
|
||||
length = [[attribs objectForKey:NSFileSize] unsignedLongLongValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[path release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (id <InputStream>) newInputStream:(id)sender {
|
||||
return [[FileInputStream alloc] initWithPath:path length:length];
|
||||
}
|
||||
- (id <InputStream>) newInputStream:(id)sender sourceOffset:(unsigned long long)theOffset sourceLength:(unsigned long long)theLength {
|
||||
return [[FileInputStream alloc] initWithPath:path offset:theOffset length:length];
|
||||
}
|
||||
@end
|
||||
44
io/FileOutputStream.h
Normal file
44
io/FileOutputStream.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "OutputStream.h"
|
||||
|
||||
@interface FileOutputStream : NSObject <OutputStream> {
|
||||
BOOL append;
|
||||
int fd;
|
||||
NSString *path;
|
||||
unsigned long long bytesWritten;
|
||||
}
|
||||
- (id)initWithPath:(NSString *)thePath append:(BOOL)isAppend;
|
||||
- (void)close;
|
||||
@end
|
||||
92
io/FileOutputStream.m
Normal file
92
io/FileOutputStream.m
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "FileOutputStream.h"
|
||||
#import "SetNSError.h"
|
||||
|
||||
@implementation FileOutputStream
|
||||
- (id)initWithPath:(NSString *)thePath append:(BOOL)isAppend {
|
||||
if (self = [super init]) {
|
||||
path = [thePath copy];
|
||||
append = isAppend;
|
||||
fd = -1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
[path release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)close {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
- (BOOL)write:(const unsigned char *)buf length:(NSUInteger)len error:(NSError **)error {
|
||||
if (fd == -1) {
|
||||
int oflag = O_WRONLY|O_CREAT;
|
||||
if (append) {
|
||||
oflag |= O_APPEND;
|
||||
} else {
|
||||
oflag |= O_TRUNC;
|
||||
}
|
||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
fd = open([path fileSystemRepresentation], oflag, mode);
|
||||
if (fd == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"%s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
int ret = 0;
|
||||
NSUInteger written = 0;
|
||||
while ((len - written) > 0) {
|
||||
write_again:
|
||||
ret = write(fd, &(buf[written]), len - written);
|
||||
if ((ret == -1) && (errno == EINTR)) {
|
||||
goto write_again;
|
||||
} else if (ret == -1) {
|
||||
SETNSERROR(@"UnixErrorDomain", errno, @"write: %s", strerror(errno));
|
||||
return NO;
|
||||
}
|
||||
written += (NSUInteger)ret;
|
||||
bytesWritten += (NSUInteger)ret;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (unsigned long long)bytesWritten {
|
||||
return bytesWritten;
|
||||
}
|
||||
@end
|
||||
43
io/FixedLengthInputStream.h
Normal file
43
io/FixedLengthInputStream.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "InputStream.h"
|
||||
@class FDInputStream;
|
||||
|
||||
@interface FixedLengthInputStream : NSObject <InputStream> {
|
||||
FDInputStream *underlyingStream;
|
||||
unsigned long long fixedLength;
|
||||
unsigned long long totalReceived;
|
||||
}
|
||||
- (id)initWithUnderlyingStream:(FDInputStream *)is length:(unsigned long long)theLength;
|
||||
@end
|
||||
69
io/FixedLengthInputStream.m
Normal file
69
io/FixedLengthInputStream.m
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright (c) 2009, Stefan Reitshamer http://www.haystacksoftware.com
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of PhotoMinds LLC or Haystack Software, nor the names of
|
||||
their contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "FixedLengthInputStream.h"
|
||||
#import "InputStreams.h"
|
||||
#import "SetNSError.h"
|
||||
#import "NSErrorCodes.h"
|
||||
#import "FDInputStream.h"
|
||||
|
||||
@implementation FixedLengthInputStream
|
||||
- (id)initWithUnderlyingStream:(FDInputStream *)is length:(unsigned long long)theLength {
|
||||
if (self = [super init]) {
|
||||
underlyingStream = [is retain];
|
||||
fixedLength = theLength;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[underlyingStream release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (unsigned char *)read:(NSUInteger *)length error:(NSError **)error {
|
||||
unsigned long long maximum = fixedLength - totalReceived;
|
||||
if (maximum == 0) {
|
||||
SETNSERROR(@"StreamsErrorDomain", ERROR_EOF, @"EOF on fixed length input stream");
|
||||
return NULL;
|
||||
}
|
||||
unsigned char *buf = [underlyingStream readMaximum:maximum length:length error:error];
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
totalReceived += (unsigned long long)(*length);
|
||||
return buf;
|
||||
}
|
||||
- (NSData *)slurp:(NSError **)error {
|
||||
return [InputStreams slurp:self error:error];
|
||||
}
|
||||
- (void)bytesWereNotUsed {
|
||||
}
|
||||
@end
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue