@end
@implementation PithosSyncDaemon
-@synthesize directoryPath, accountsDictionary, pithos;
+@synthesize directoryPath, accountsDictionary, skipHidden, pithos;
@synthesize accountsNames, accountsPithosContainers;
@synthesize lastCompletedSync, remoteObjects, previousRemoteObjects, storedLocalObjectStates, currentLocalObjectStates;
@synthesize pithosStateFilePath, tempDownloadsDirPath, tempTrashDirPath;
- (id)initWithDirectoryPath:(NSString *)aDirectoryPath
pithosAccount:(PithosAccount *)aPithosAccount
accountsDictionary:(NSDictionary *)anAccountsDictionary
+ skipHidden:(BOOL)aSkipHidden
resetLocalState:(BOOL)resetLocalState {
if ((self = [super init])) {
directoryPath = [aDirectoryPath copy];
- pithosAccount = [aPithosAccount retain];
+ pithosAccount = aPithosAccount;
self.accountsDictionary = anAccountsDictionary;
+ skipHidden = aSkipHidden;
self.pithos = pithosAccount.pithos;
activityFacility = [PithosActivityFacility defaultPithosActivityFacility];
}
- (void)loadLocalState {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if ([[NSFileManager defaultManager] fileExistsAtPath:self.pithosStateFilePath])
- self.storedLocalObjectStates = [NSKeyedUnarchiver unarchiveObjectWithFile:self.pithosStateFilePath];
- else
- self.storedLocalObjectStates = [NSMutableDictionary dictionary];
- if (!storedLocalObjectStates)
- self.storedLocalObjectStates = [NSMutableDictionary dictionary];
- for (NSString *accountName in accountsNames) {
- NSMutableDictionary *accountStoredLocalObjectStates = [storedLocalObjectStates objectForKey:accountName];
- if (!accountStoredLocalObjectStates) {
- accountStoredLocalObjectStates = [NSMutableDictionary dictionary];
- [storedLocalObjectStates setObject:accountStoredLocalObjectStates forKey:accountName];
- }
- for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
- if (![accountStoredLocalObjectStates objectForKey:pithosContainer.name])
- [accountStoredLocalObjectStates setObject:[NSMutableDictionary dictionary] forKey:pithosContainer.name];
+ @autoreleasepool {
+ if ([[NSFileManager defaultManager] fileExistsAtPath:self.pithosStateFilePath])
+ self.storedLocalObjectStates = [NSKeyedUnarchiver unarchiveObjectWithFile:self.pithosStateFilePath];
+ else
+ self.storedLocalObjectStates = [NSMutableDictionary dictionary];
+ if (!storedLocalObjectStates)
+ self.storedLocalObjectStates = [NSMutableDictionary dictionary];
+ for (NSString *accountName in accountsNames) {
+ NSMutableDictionary *accountStoredLocalObjectStates = [storedLocalObjectStates objectForKey:accountName];
+ if (!accountStoredLocalObjectStates) {
+ accountStoredLocalObjectStates = [NSMutableDictionary dictionary];
+ [storedLocalObjectStates setObject:accountStoredLocalObjectStates forKey:accountName];
+ }
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ if (![accountStoredLocalObjectStates objectForKey:pithosContainer.name])
+ [accountStoredLocalObjectStates setObject:[NSMutableDictionary dictionary] forKey:pithosContainer.name];
+ }
}
}
- [pool drain];
}
- (void)resetLocalStateWithAll:(BOOL)all {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- self.lastCompletedSync = nil;
- if (all) {
- self.storedLocalObjectStates = [NSMutableDictionary dictionary];
- [self saveLocalState]; // Save an empty dictionary
- [self loadLocalState]; // Load to populate with containers
- [self saveLocalState]; // Save again
- if (self.tempDownloadsDirPath)
- [PithosUtilities removeContentsAtPath:self.tempDownloadsDirPath];
- } else {
- // Remove containers that don't interest us anymore and save
- if (!storedLocalObjectStates)
- [self loadLocalState];
- for (NSString *accountName in storedLocalObjectStates) {
- NSMutableDictionary *accountStoredLocalObjectStates = [storedLocalObjectStates objectForKey:accountName];
- NSDictionary *containersDictionary = [accountsDictionary objectForKey:accountName];
- if (!containersDictionary) {
- if (self.tempDownloadsDirPath) {
- if ([accountName isEqualToString:@""]) {
- for (NSString *containerName in accountStoredLocalObjectStates) {
- [PithosUtilities removeContentsAtPath:[self.tempDownloadsDirPath stringByAppendingPathComponent:containerName]];
+ @autoreleasepool {
+ self.lastCompletedSync = nil;
+ if (all) {
+ self.storedLocalObjectStates = [NSMutableDictionary dictionary];
+ [self saveLocalState]; // Save an empty dictionary
+ [self loadLocalState]; // Load to populate with containers
+ [self saveLocalState]; // Save again
+ if (self.tempDownloadsDirPath)
+ [PithosUtilities removeContentsAtPath:self.tempDownloadsDirPath];
+ } else {
+ // Remove containers that don't interest us anymore and save
+ if (!storedLocalObjectStates)
+ [self loadLocalState];
+ for (NSString *accountName in storedLocalObjectStates) {
+ NSMutableDictionary *accountStoredLocalObjectStates = [storedLocalObjectStates objectForKey:accountName];
+ NSDictionary *containersDictionary = [accountsDictionary objectForKey:accountName];
+ if (!containersDictionary) {
+ if (self.tempDownloadsDirPath) {
+ if ([accountName isEqualToString:@""]) {
+ for (NSString *containerName in accountStoredLocalObjectStates) {
+ [PithosUtilities removeContentsAtPath:[self.tempDownloadsDirPath stringByAppendingPathComponent:containerName]];
+ }
+ } else {
+ [PithosUtilities removeContentsAtPath:[[self.tempDownloadsDirPath stringByAppendingPathComponent:@"shared with me"]
+ stringByAppendingPathComponent:accountName]];
}
- } else {
- [PithosUtilities removeContentsAtPath:[[self.tempDownloadsDirPath stringByAppendingPathComponent:@"shared to me"]
- stringByAppendingPathComponent:accountName]];
}
- }
- [storedLocalObjectStates removeObjectForKey:accountName];
- } else {
- // Check the account's containers
- for (NSString *containerName in accountStoredLocalObjectStates) {
- if (![containersDictionary objectForKey:containerName]) {
- if ([accountName isEqualToString:@""])
- [PithosUtilities removeContentsAtPath:[self.tempDownloadsDirPath stringByAppendingPathComponent:containerName]];
- else
- [PithosUtilities removeContentsAtPath:[[[self.tempDownloadsDirPath stringByAppendingPathComponent:@"shared to me"]
- stringByAppendingPathComponent:accountName]
- stringByAppendingPathComponent:containerName]];
- [accountStoredLocalObjectStates removeObjectForKey:containerName];
+ [storedLocalObjectStates removeObjectForKey:accountName];
+ } else {
+ // Check the account's containers
+ for (NSString *containerName in accountStoredLocalObjectStates) {
+ if (![containersDictionary objectForKey:containerName]) {
+ if ([accountName isEqualToString:@""])
+ [PithosUtilities removeContentsAtPath:[self.tempDownloadsDirPath stringByAppendingPathComponent:containerName]];
+ else
+ [PithosUtilities removeContentsAtPath:[[[self.tempDownloadsDirPath stringByAppendingPathComponent:@"shared with me"]
+ stringByAppendingPathComponent:accountName]
+ stringByAppendingPathComponent:containerName]];
+ [accountStoredLocalObjectStates removeObjectForKey:containerName];
+ }
}
}
}
+ [self saveLocalState];
}
- [self saveLocalState];
}
- [pool drain];
}
- (void)saveLocalState {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [NSKeyedArchiver archiveRootObject:storedLocalObjectStates toFile:self.pithosStateFilePath];
- [pool drain];
+ @autoreleasepool {
+ [NSKeyedArchiver archiveRootObject:storedLocalObjectStates toFile:self.pithosStateFilePath];
+ }
}
- (void)resetDaemon {
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self resetDaemon];
- [callbackQueue release];
- [networkQueue release];
- [tempTrashDirPath release];
- [tempDownloadsDirPath release];
- [pithosStateFilePath release];
- [currentLocalObjectStates release];
- [storedLocalObjectStates release];
- [previousRemoteObjects release];
- [remoteObjects release];
- [objects release];
- [lastCompletedSync release];
- [accountsPithosContainers release];
- [accountsNames release];
- [pithos release];
- [accountsDictionary release];
- [pithosAccount release];
- [directoryPath release];
- [super dealloc];
}
#pragma mark -
- (NSString *)pithosStateFilePath {
if (!pithosStateFilePath) {
- pithosStateFilePath = [[[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
+ pithosStateFilePath = [[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]]
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-PithosLocalObjectStates.archive",
- pithosAccount.uniqueName]] retain];
+ pithosAccount.uniqueName]];
NSString *pithosStateFileDirPath = [pithosStateFilePath stringByDeletingLastPathComponent];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory;
// pithosStateFilePath = nil;
// XXX create a dir using mktmps?
}
- return [[pithosStateFilePath copy] autorelease];
+ return [pithosStateFilePath copy];
}
- (NSString *)tempDownloadsDirPath {
if (!tempDownloadsDirPath) {
- tempDownloadsDirPath = [[[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
+ tempDownloadsDirPath = [[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]]
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-TempDownloads",
- pithosAccount.uniqueName]] retain];
+ pithosAccount.uniqueName]];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory;
BOOL fileExists = [fileManager fileExistsAtPath:tempDownloadsDirPath isDirectory:&isDirectory];
- (NSString *)tempTrashDirPath {
if (!tempTrashDirPath) {
- tempTrashDirPath = [[[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
+ tempTrashDirPath = [[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]]
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-TempTrash",
- pithosAccount.uniqueName]] retain];
+ pithosAccount.uniqueName]];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory;
BOOL fileExists = [fileManager fileExistsAtPath:tempTrashDirPath isDirectory:&isDirectory];
if (aDirectoryPath && ![aDirectoryPath isEqualToString:directoryPath]) {
[self resetDaemon];
[self resetLocalStateWithAll:YES];
- [directoryPath release];
directoryPath = [aDirectoryPath copy];
}
}
if (reset)
[self resetDaemon];
- [accountsDictionary release];
accountsDictionary = [anAccountsDictionary copy];
accountsCount = [accountsDictionary count];
- (void)setPithos:(ASIPithos *)aPithos {
if (!pithos) {
- pithos = [[ASIPithos pithos] retain];
- pithos.authUser = [[aPithos.authUser copy] autorelease];
- pithos.authToken = [[aPithos.authToken copy] autorelease];
- pithos.storageURLPrefix = [[aPithos.storageURLPrefix copy] autorelease];
- pithos.authURL = [[aPithos.authURL copy] autorelease];
- pithos.publicURLPrefix = [[aPithos.publicURLPrefix copy] autorelease];
+ pithos = [ASIPithos pithos];
+ pithos.authUser = [aPithos.authUser copy];
+ pithos.authToken = [aPithos.authToken copy];
+ pithos.storageURLPrefix = [aPithos.storageURLPrefix copy];
+ pithos.authURL = [aPithos.authURL copy];
+ pithos.publicURLPrefix = [aPithos.publicURLPrefix copy];
+ pithos.userCatalogURL = [aPithos.userCatalogURL copy];
}
if (aPithos &&
(![aPithos.authUser isEqualToString:pithos.authUser] ||
if (![aPithos.authUser isEqualToString:pithos.authUser] ||
![aPithos.storageURLPrefix isEqualToString:pithos.storageURLPrefix])
[self resetLocalStateWithAll:YES];
- pithos.authUser = [[aPithos.authUser copy] autorelease];
- pithos.authToken = [[aPithos.authToken copy] autorelease];
- pithos.storageURLPrefix = [[aPithos.storageURLPrefix copy] autorelease];
- pithos.authURL = [[aPithos.authURL copy] autorelease];
- pithos.publicURLPrefix = [[aPithos.publicURLPrefix copy] autorelease];
- }
+ pithos.authUser = [aPithos.authUser copy];
+ pithos.authToken = [aPithos.authToken copy];
+ pithos.storageURLPrefix = [aPithos.storageURLPrefix copy];
+ pithos.authURL = [aPithos.authURL copy];
+ pithos.publicURLPrefix = [aPithos.publicURLPrefix copy];
+ pithos.userCatalogURL = [aPithos.userCatalogURL copy];
+ }
}
#pragma mark -
if ([accountName isEqualToString:@""])
return [directoryPath stringByAppendingPathComponent:containerName];
else
- return [[[directoryPath stringByAppendingPathComponent:@"shared to me"]
+ return [[[directoryPath stringByAppendingPathComponent:@"shared with me"]
stringByAppendingPathComponent:accountName]
stringByAppendingPathComponent:containerName];
}
if ([accountName isEqualToString:@""])
return containerName;
else
- return [[[NSString stringWithString:@"shared to me"]
- stringByAppendingPathComponent:accountName]
- stringByAppendingPathComponent:containerName];
+ return [[@"shared with me" stringByAppendingPathComponent:accountName] stringByAppendingPathComponent:containerName];
}
#pragma mark -
syncIncomplete = YES;
if (syncOperationCount == 0) {
// XXX This shouldn't happen, maybe change operationCount to a BOOL as operationsPending in browser
- NSLog(@"Sync::WARNING: tried to decrease syncOperationCount when 0");
+ DLog(@"Sync::WARNING: tried to decrease syncOperationCount when 0");
return;
}
syncOperationCount--;
}
- (void)emptyTempTrash {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSString *trashDirPath = self.tempTrashDirPath;
- if (trashDirPath) {
- NSFileManager *fileManager = [NSFileManager defaultManager];
- NSError *error = nil;
-// NSArray *subPaths = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:trashDirPath error:&error];
- NSArray *subPaths = [fileManager contentsOfDirectoryAtPath:trashDirPath error:&error];
- if (error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ @autoreleasepool {
+ NSString *trashDirPath = self.tempTrashDirPath;
+ if (trashDirPath) {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error = nil;
+// NSArray *subPaths = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:trashDirPath error:&error];
+ NSArray *subPaths = [fileManager contentsOfDirectoryAtPath:trashDirPath error:&error];
+ if (error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", trashDirPath]
error:error];
- });
- [pool drain];
- return;
- }
- if ([subPaths count]) {
-// NSMutableArray *subURLs = [NSMutableArray arrayWithCapacity:[subPaths count]];
-// for (NSString *subPath in subPaths) {
-// [subURLs addObject:[NSURL fileURLWithPath:[trashDirPath stringByAppendingPathComponent:subPath]]];
-// }
-// [self syncOperationStarted];
-// [[NSWorkspace sharedWorkspace] recycleURLs:subURLs completionHandler:^(NSDictionary *newURLs, NSError *error) {
-// if (error) {
-// dispatch_async(dispatch_get_main_queue(), ^{
-// [PithosUtilities fileActionFailedAlertWithTitle:@"Move to Trash Error"
-// message:@"Cannot move files to Trash"
+ return;
+ }
+ if ([subPaths count]) {
+// NSMutableArray *subURLs = [NSMutableArray arrayWithCapacity:[subPaths count]];
+// for (NSString *subPath in subPaths) {
+// [subURLs addObject:[NSURL fileURLWithPath:[trashDirPath stringByAppendingPathComponent:subPath]]];
+// }
+// [self syncOperationStarted];
+// [[NSWorkspace sharedWorkspace] recycleURLs:subURLs completionHandler:^(NSDictionary *newURLs, NSError *error) {
+// if (error) {
+// [PithosUtilities fileActionFailedAlertWithTitle:@"Move to Trash Error"
+// message:@"Cannot move files to Trash"
// error:error];
-// });
-// }
-// [self syncOperationFinishedWithSuccess:YES];
-// }];
- for (NSString *subPath in subPaths) {
- NSString *subFilePath = [trashDirPath stringByAppendingPathComponent:subPath];
- error = nil;
- if (![fileManager removeItemAtPath:subFilePath error:&error] || error)
- dispatch_async(dispatch_get_main_queue(), ^{
+// }
+// [self syncOperationFinishedWithSuccess:YES];
+// }];
+ for (NSString *subPath in subPaths) {
+ NSString *subFilePath = [trashDirPath stringByAppendingPathComponent:subPath];
+ error = nil;
+ if (![fileManager removeItemAtPath:subFilePath error:&error] || error)
[PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
message:[NSString stringWithFormat:@"Cannot remove file at '%@'", subFilePath]
error:error];
- });
+ }
}
}
}
- [pool drain];
}
- (BOOL)moveToTempTrashFile:(NSString *)filePath
accountName:(NSString *)accountName
pithosContainer:(ASIPithosContainer *)pithosContainer {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if (!self.tempTrashDirPath) {
- [pool drain];
- return NO;
- }
- NSFileManager *fileManager = [NSFileManager defaultManager];
- BOOL isDirectory;
- BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
- NSError *error = nil;
- NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
- NSString *newFilePath = [filePath stringByReplacingOccurrencesOfString:containerDirectoryPath withString:self.tempTrashDirPath];
- NSString *newDirPath = [newFilePath stringByDeletingLastPathComponent];
- if (fileExists && isDirectory) {
- NSArray *subPaths = [fileManager subpathsOfDirectoryAtPath:filePath error:&error];
- if (error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ @autoreleasepool {
+ if (!self.tempTrashDirPath)
+ return NO;
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory;
+ BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
+ NSError *error = nil;
+ NSString *newFilePath = [filePath stringByReplacingOccurrencesOfString:directoryPath withString:self.tempTrashDirPath];
+ NSString *newDirPath = [newFilePath stringByDeletingLastPathComponent];
+ if (fileExists && isDirectory) {
+ NSArray *subPaths = [fileManager subpathsOfDirectoryAtPath:filePath error:&error];
+ if (error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", filePath]
error:error];
- });
- [pool drain];
- return NO;
- }
- if (![fileManager createDirectoryAtPath:newDirPath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ return NO;
+ }
+ if (![fileManager createDirectoryAtPath:newDirPath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
message:[NSString stringWithFormat:@"Cannot create directory at '%@'", newDirPath]
error:error];
- });
- [pool drain];
- return NO;
- }
- if (![fileManager moveItemAtPath:filePath toPath:newFilePath error:&error] || error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ return NO;
+ }
+ if (![fileManager moveItemAtPath:filePath toPath:newFilePath error:&error] || error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error"
message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'",
filePath, newFilePath]
error:error];
- });
- [pool drain];
- return NO;
- }
- PithosLocalObjectState *currentState = [currentLocalObjectStates objectForKey:filePath];
- if (currentState) {
- currentState.filePath = newFilePath;
- [currentLocalObjectStates setObject:currentState forKey:newFilePath];
- [currentLocalObjectStates removeObjectForKey:filePath];
- } else {
- [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newFilePath
- blockHash:pithosContainer.blockHash
- blockSize:pithosContainer.blockSize]
- forKey:newFilePath];
- }
- for (NSString *subPath in subPaths) {
- NSString *subFilePath = [filePath stringByAppendingPathComponent:subPath];
- NSString *newSubFilePath = [subFilePath stringByReplacingOccurrencesOfString:containerDirectoryPath
- withString:self.tempTrashDirPath];
- currentState = [currentLocalObjectStates objectForKey:subFilePath];
+ return NO;
+ }
+ PithosLocalObjectState *currentState = [currentLocalObjectStates objectForKey:filePath];
if (currentState) {
- currentState.filePath = newSubFilePath;
- [currentLocalObjectStates setObject:currentState forKey:newSubFilePath];
- [currentLocalObjectStates removeObjectForKey:subFilePath];
+ currentState.filePath = newFilePath;
+ [currentLocalObjectStates setObject:currentState forKey:newFilePath];
+ [currentLocalObjectStates removeObjectForKey:filePath];
} else {
- [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newSubFilePath
+ [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newFilePath
blockHash:pithosContainer.blockHash
blockSize:pithosContainer.blockSize]
- forKey:newSubFilePath];
- }
- }
- } else if (fileExists && !isDirectory) {
- if (![fileManager createDirectoryAtPath:newDirPath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ forKey:newFilePath];
+ }
+ for (NSString *subPath in subPaths) {
+ NSString *subFilePath = [filePath stringByAppendingPathComponent:subPath];
+ NSString *newSubFilePath = [subFilePath stringByReplacingOccurrencesOfString:directoryPath
+ withString:self.tempTrashDirPath];
+ currentState = [currentLocalObjectStates objectForKey:subFilePath];
+ if (currentState) {
+ currentState.filePath = newSubFilePath;
+ [currentLocalObjectStates setObject:currentState forKey:newSubFilePath];
+ [currentLocalObjectStates removeObjectForKey:subFilePath];
+ } else {
+ [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newSubFilePath
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize]
+ forKey:newSubFilePath];
+ }
+ }
+ } else if (fileExists && !isDirectory) {
+ if (![fileManager createDirectoryAtPath:newDirPath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
message:[NSString stringWithFormat:@"Cannot create directory at '%@'", newDirPath]
error:error];
- });
- [pool drain];
- return NO;
- }
- if (![fileManager moveItemAtPath:filePath toPath:newFilePath error:&error] || error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ return NO;
+ }
+ if (![fileManager moveItemAtPath:filePath toPath:newFilePath error:&error] || error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error"
message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'",
filePath, newFilePath]
error:error];
- });
- [pool drain];
- return NO;
- }
- PithosLocalObjectState *currentState = [currentLocalObjectStates objectForKey:filePath];
- if (currentState) {
- currentState.filePath = newFilePath;
- [currentLocalObjectStates setObject:currentState forKey:newFilePath];
- [currentLocalObjectStates removeObjectForKey:filePath];
- } else {
- [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newFilePath
- blockHash:pithosContainer.blockHash
- blockSize:pithosContainer.blockSize]
- forKey:newFilePath];
+ return NO;
+ }
+ PithosLocalObjectState *currentState = [currentLocalObjectStates objectForKey:filePath];
+ if (currentState) {
+ currentState.filePath = newFilePath;
+ [currentLocalObjectStates setObject:currentState forKey:newFilePath];
+ [currentLocalObjectStates removeObjectForKey:filePath];
+ } else {
+ [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newFilePath
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize]
+ forKey:newFilePath];
+ }
}
}
- [pool drain];
return YES;
}
- (BOOL)findLocalCopyForObjectWithHash:(NSString *)hash forFile:(NSString *)filePath {
if ([hash length] != 64)
return NO;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- PithosLocalObjectState *localState;
- NSFileManager *fileManager = [NSFileManager defaultManager];
- BOOL isDirectory;
- NSError *error = nil;
- for (NSString *localFilePath in currentLocalObjectStates) {
- localState = [currentLocalObjectStates objectForKey:localFilePath];
- if (!localState.isDirectory && [hash isEqualToString:localState.hash] &&
- [fileManager fileExistsAtPath:localFilePath isDirectory:&isDirectory] && !isDirectory) {
- if ([localFilePath hasPrefix:directoryPath]) {
- if (![fileManager copyItemAtPath:localFilePath toPath:filePath error:&error] || error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ @autoreleasepool {
+ PithosLocalObjectState *localState;
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory;
+ NSError *error = nil;
+ for (NSString *localFilePath in currentLocalObjectStates) {
+ localState = [currentLocalObjectStates objectForKey:localFilePath];
+ if (!localState.isDirectory && [hash isEqualToString:localState.hash] &&
+ [fileManager fileExistsAtPath:localFilePath isDirectory:&isDirectory] && !isDirectory) {
+ if ([localFilePath hasPrefix:directoryPath]) {
+ if (![fileManager copyItemAtPath:localFilePath toPath:filePath error:&error] || error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Copy File Error"
message:[NSString stringWithFormat:@"Cannot copy file at '%@' to '%@'",
localFilePath, filePath]
error:error];
- });
- } else {
- [pool drain];
- return YES;
- }
- } else if (self.tempTrashDirPath && [localFilePath hasPrefix:self.tempTrashDirPath]) {
- if (![fileManager moveItemAtPath:localFilePath toPath:filePath error:&error] || error) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ } else {
+ return YES;
+ }
+ } else if (self.tempTrashDirPath && [localFilePath hasPrefix:self.tempTrashDirPath]) {
+ if (![fileManager moveItemAtPath:localFilePath toPath:filePath error:&error] || error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error"
message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'",
localFilePath, filePath]
error:error];
- });
- } else {
- localState.filePath = filePath;
- [currentLocalObjectStates setObject:localState forKey:filePath];
- [currentLocalObjectStates removeObjectForKey:localFilePath];
- [pool drain];
- return YES;
+ } else {
+ localState.filePath = filePath;
+ [currentLocalObjectStates setObject:localState forKey:filePath];
+ [currentLocalObjectStates removeObjectForKey:localFilePath];
+ return YES;
+ }
}
}
}
}
- [pool drain];
return NO;
}
localFilePath:(NSString *)filePath
accountName:(NSString *)accountName
pithosContainer:(ASIPithosContainer *)pithosContainer {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- NSError *error;
- BOOL isDirectory;
- BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
- NSString *fileDirectoryPath = [filePath stringByDeletingLastPathComponent];
- NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
- objectForKey:pithosContainer.name];
- PithosLocalObjectState *storedState = [containerStoredLocalObjectStates objectForKey:object.name];
- // Remote updated info
- NSError *remoteError;
- BOOL remoteIsDirectory;
- BOOL remoteObjectExists = [PithosUtilities objectExistsAtPithos:pithos
- containerName:pithosContainer.name
- objectName:object.name
- error:&remoteError
- isDirectory:&remoteIsDirectory
- sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
- if (!object || !object.objectHash) {
- // Delete local object
- if (![accountName isEqualToString:@""]) {
- // If "shared to me" skip
- [pool drain];
- return;
- }
- if (remoteObjectExists) {
- // Remote object created in the meantime, just mark the sync cycle as incomplete, but do delete the local object
- syncIncomplete = YES;
- }
- NSLog(@"Sync::delete local object: %@", filePath);
- if (!fileExists || [self moveToTempTrashFile:filePath accountName:accountName pithosContainer:pithosContainer]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Deleting '%@/%@' locally (finished)",
- pithosContainer.name, object.name]
- pithosAccount:pithosAccount];
- });
- [containerStoredLocalObjectStates removeObjectForKey:object.name];
- [self saveLocalState];
- }
- } else if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
- // Create local directory object
- if (!remoteObjectExists || !remoteIsDirectory) {
- // Remote directory object deleted or changed to a file object in the meantime, mark the sync cycle as incomplete and skip
- syncIncomplete = YES;
- [pool drain];
- return;
- }
- NSLog(@"Sync::create local directory object: %@", filePath);
- BOOL directoryCreated = NO;
- if (!fileExists || (!isDirectory && [self moveToTempTrashFile:filePath accountName:accountName pithosContainer:pithosContainer])) {
- NSLog(@"Sync::local directory object doesn't exist: %@", filePath);
- error = nil;
- if (![fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
+ @autoreleasepool {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error;
+ BOOL isDirectory;
+ BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
+ NSString *fileDirectoryPath = [filePath stringByDeletingLastPathComponent];
+ NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name];
+ PithosLocalObjectState *storedState = [containerStoredLocalObjectStates objectForKey:object.name];
+ // Remote updated info
+ NSError *remoteError;
+ BOOL remoteIsDirectory;
+ BOOL remoteObjectExists = [PithosUtilities objectExistsAtPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name
+ error:&remoteError
+ isDirectory:&remoteIsDirectory
+ sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
+ if (!object || !object.objectHash) {
+ // Delete local object
+ if (![accountName isEqualToString:@""])
+ // If "shared with me" skip
+ return;
+ if (remoteObjectExists) {
+ // Remote object created in the meantime, just mark the sync cycle as incomplete, but do delete the local object
+ syncIncomplete = YES;
+ }
+ DLog(@"Sync::delete local object: %@", filePath);
+ if (!fileExists || [self moveToTempTrashFile:filePath accountName:accountName pithosContainer:pithosContainer]) {
dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility startAndEndActivityWithType:PithosActivityOther
+ message:[NSString stringWithFormat:@"Sync: Deleting '%@/%@' locally (finished)",
+ pithosContainer.name, object.name]
+ pithosAccount:pithosAccount];
+ });
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
+ [self saveLocalState];
+ }
+ } else if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
+ // Create local directory object
+ if (!remoteObjectExists || !remoteIsDirectory) {
+ // Remote directory object deleted or changed to a file object in the meantime, mark the sync cycle as incomplete and skip
+ syncIncomplete = YES;
+ return;
+ }
+ DLog(@"Sync::create local directory object: %@", filePath);
+ BOOL directoryCreated = NO;
+ if (!fileExists || (!isDirectory && [self moveToTempTrashFile:filePath accountName:accountName pithosContainer:pithosContainer])) {
+ DLog(@"Sync::local directory object doesn't exist: %@", filePath);
+ error = nil;
+ if (![fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
message:[NSString stringWithFormat:@"Cannot create directory at '%@'", filePath]
error:error];
- });
+ } else {
+ directoryCreated = YES;
+ storedState.filePath = filePath;
+ storedState.isDirectory = YES;
+ [self saveLocalState];
+ }
} else {
+ DLog(@"Sync::local directory object exists: %@", filePath);
directoryCreated = YES;
- storedState.filePath = filePath;
- storedState.isDirectory = YES;
- [self saveLocalState];
}
- } else {
- NSLog(@"Sync::local directory object exists: %@", filePath);
- directoryCreated = YES;
- }
- if (directoryCreated)
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Creating directory '%@/%@' locally (finished)",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name],
- object.name]
- pithosAccount:pithosAccount];
- });
- } else if (object.bytes == 0) {
- // Create local object with zero length
- if (!remoteObjectExists || remoteIsDirectory) {
- // Remote file object deleted or changed to a directory object in the meantime, mark the sync cycle as incomplete and skip
- syncIncomplete = YES;
- [pool drain];
- return;
- }
- NSLog(@"Sync::create local zero length object: %@", filePath);
- BOOL fileCreated = NO;
- if (!fileExists ||
- ((isDirectory || [PithosUtilities bytesOfFile:filePath]) &&
- [self moveToTempTrashFile:filePath accountName:accountName pithosContainer:pithosContainer])) {
- NSLog(@"Sync::local zero length object doesn't exist: %@", filePath);
- // Create directory of the file, if it doesn't exist
- error = nil;
- if (![PithosUtilities safeCreateDirectory:fileDirectoryPath error:&error]) {
+ if (directoryCreated)
dispatch_async(dispatch_get_main_queue(), ^{
- [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
- message:[NSString stringWithFormat:@"Cannot create directory at '%@'", fileDirectoryPath]
- error:error];
+ [activityFacility startAndEndActivityWithType:PithosActivityOther
+ message:[NSString stringWithFormat:@"Sync: Creating directory '%@/%@' locally (finished)",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
+ pithosAccount:pithosAccount];
});
+ } else if (object.bytes == 0) {
+ // Create local object with zero length
+ if (!remoteObjectExists || remoteIsDirectory) {
+ // Remote file object deleted or changed to a directory object in the meantime, mark the sync cycle as incomplete and skip
+ syncIncomplete = YES;
+ return;
}
- error = nil;
- if (![fileManager createFileAtPath:filePath contents:nil attributes:nil]) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ DLog(@"Sync::create local zero length object: %@", filePath);
+ BOOL fileCreated = NO;
+ if (!fileExists ||
+ ((isDirectory || [PithosUtilities bytesOfFile:filePath]) &&
+ [self moveToTempTrashFile:filePath accountName:accountName pithosContainer:pithosContainer])) {
+ DLog(@"Sync::local zero length object doesn't exist: %@", filePath);
+ // Create directory of the file, if it doesn't exist
+ error = nil;
+ if (![PithosUtilities safeCreateDirectory:fileDirectoryPath error:&error]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
+ message:[NSString stringWithFormat:@"Cannot create directory at '%@'", fileDirectoryPath]
+ error:error];
+ });
+ }
+ error = nil;
+ if (![fileManager createFileAtPath:filePath contents:nil attributes:nil]) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Create File Error"
message:[NSString stringWithFormat:@"Cannot create file at '%@'", filePath]
error:error];
- });
+ } else {
+ fileCreated = YES;
+ storedState.filePath = filePath;
+ storedState.hash = object.objectHash;
+ storedState.tmpFilePath = nil;
+ [self saveLocalState];
+ }
} else {
+ DLog(@"Sync::local zero length object exists: %@", filePath);
fileCreated = YES;
+ }
+ if (fileCreated)
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility startAndEndActivityWithType:PithosActivityOther
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
+ pithosAccount:pithosAccount];
+ });
+ } else if (storedState.tmpFilePath == nil) {
+ // Create new local object
+ if (!remoteObjectExists || remoteIsDirectory) {
+ // Remote file object deleted or changed to a directory object in the meantime, mark the sync cycle as incomplete and skip
+ syncIncomplete = YES;
+ return;
+ }
+ // Create directory of the file, if it doesn't exist
+ error = nil;
+ if (![PithosUtilities safeCreateDirectory:fileDirectoryPath error:&error]) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
+ message:[NSString stringWithFormat:@"Cannot create directory at '%@'", fileDirectoryPath]
+ error:error];
+ }
+ // Check first if a local copy exists
+ if ([self findLocalCopyForObjectWithHash:object.objectHash forFile:filePath]) {
storedState.filePath = filePath;
storedState.hash = object.objectHash;
- storedState.tmpFilePath = nil;
[self saveLocalState];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility startAndEndActivityWithType:PithosActivityOther
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
+ pithosAccount:pithosAccount];
+ });
+ } else {
+ [self syncOperationStarted];
+ __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ object:object
+ blockIndex:0
+ blockSize:pithosContainer.blockSize];
+ if (![accountName isEqualToString:@""])
+ [objectRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Downloading '%@/%@'",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload
+ message:[messagePrefix stringByAppendingString:@" (0%%)"]
+ totalBytes:object.bytes
+ currentBytes:0
+ pithosAccount:pithosAccount];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity withMessage:activity.message];
+ });
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ accountName, @"accountName",
+ pithosContainer, @"pithosContainer",
+ object, @"pithosObject",
+ messagePrefix, @"messagePrefix",
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, (NSUInteger)ceil((object.bytes +0.0)/(pithosContainer.blockSize + 0.0)))], @"missingBlocks",
+ [NSNumber numberWithUnsignedInteger:0], @"missingBlockIndex",
+ filePath, @"filePath",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(downloadObjectBlockFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ nil];
+ [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
+ [activityFacility updateActivity:activity
+ withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
+ messagePrefix, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ totalBytes:activity.totalBytes
+ currentBytes:(activity.currentBytes + size)];
+ }];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]];
}
} else {
- NSLog(@"Sync::local zero length object exists: %@", filePath);
- fileCreated = YES;
- }
- if (fileCreated)
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name],
- object.name]
- pithosAccount:pithosAccount];
- });
- } else if (storedState.tmpFilePath == nil) {
- // Create new local object
- if (!remoteObjectExists || remoteIsDirectory) {
- // Remote file object deleted or changed to a directory object in the meantime, mark the sync cycle as incomplete and skip
- syncIncomplete = YES;
- [pool drain];
- return;
- }
- // Create directory of the file, if it doesn't exist
- error = nil;
- if (![PithosUtilities safeCreateDirectory:fileDirectoryPath error:&error]) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ // Resume local object download
+ if (!remoteObjectExists || remoteIsDirectory) {
+ // Remote file object deleted or changed to a directory object in the meantime, mark the sync cycle as incomplete and skip
+ syncIncomplete = YES;
+ return;
+ }
+ // Create directory of the file, if it doesn't exist
+ error = nil;
+ if (![PithosUtilities safeCreateDirectory:fileDirectoryPath error:&error]) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
message:[NSString stringWithFormat:@"Cannot create directory at '%@'", fileDirectoryPath]
error:error];
- });
+ }
+ // Check first if a local copy exists
+ if ([self findLocalCopyForObjectWithHash:object.objectHash forFile:filePath]) {
+ storedState.filePath = filePath;
+ storedState.hash = object.objectHash;
+ // Delete incomplete temp download
+ storedState.tmpFilePath = nil;
+ [self saveLocalState];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility startAndEndActivityWithType:PithosActivityOther
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
+ pithosAccount:pithosAccount];
+ });
+ } else {
+ [self syncOperationStarted];
+ ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectHashmapRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name];
+ if (![accountName isEqualToString:@""])
+ [objectRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Downloading '%@/%@'",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload
+ message:[messagePrefix stringByAppendingString:@" (0%%)"]
+ totalBytes:object.bytes
+ currentBytes:0
+ pithosAccount:pithosAccount];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity withMessage:activity.message];
+ });
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ accountName, @"accountName",
+ pithosContainer, @"pithosContainer",
+ object, @"pithosObject",
+ messagePrefix, @"messagePrefix",
+ filePath, @"filePath",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(downloadObjectHashMapFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ nil];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]];
+ }
}
- // Check first if a local copy exists
- if ([self findLocalCopyForObjectWithHash:object.objectHash forFile:filePath]) {
- storedState.filePath = filePath;
- storedState.hash = object.objectHash;
- [self saveLocalState];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name],
- object.name]
- pithosAccount:pithosAccount];
- });
- } else {
- [self syncOperationStarted];
- __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
- containerName:pithosContainer.name
- object:object
- blockIndex:0
- blockSize:pithosContainer.blockSize];
+ }
+}
+
+-(void)updateServerStateWithCurrentState:(PithosLocalObjectState *)currentState
+ object:(ASIPithosObject *)object
+ localFilePath:(NSString *)filePath
+ accountName:(NSString *)accountName
+ pithosContainer:(ASIPithosContainer *)pithosContainer {
+ @autoreleasepool {
+ [self syncOperationStarted];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory;
+ BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
+ if (currentState.isDirectory) {
+ // Create remote directory object
+ if (![accountName isEqualToString:@""]) {
+ if (!object.allowedTo) {
+ NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
+ NSString *objectAncestorName = [object.name stringByDeletingLastPathComponent];
+ while ([objectAncestorName length] && !object.allowedTo) {
+ object.allowedTo = [[containerRemoteObjects objectForKey:objectAncestorName] allowedTo];
+ objectAncestorName = [objectAncestorName stringByDeletingLastPathComponent];
+ }
+ }
+ if (![object.allowedTo isEqualToString:@"write"]) {
+ // If read-only "shared with me" skip
+ [self syncOperationFinishedWithSuccess:YES];
+ return;
+ }
+ }
+ if (!fileExists || !isDirectory) {
+ // Local directory object deleted or changed to a file in the meantime, mark the sync cycle as incomplete and skip
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+ ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name
+ eTag:nil
+ contentType:@"application/directory"
+ contentEncoding:nil
+ contentDisposition:nil
+ manifest:nil
+ sharing:nil
+ isPublic:ASIPithosObjectRequestPublicIgnore
+ metadata:nil
+ data:[NSData data]];
if (![accountName isEqualToString:@""])
[objectRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
objectRequest.delegate = self;
objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Downloading '%@/%@'",
+ NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Creating directory '%@/%@'",
[self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload
- message:[messagePrefix stringByAppendingString:@" (0%%)"]
- totalBytes:object.bytes
- currentBytes:0
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory
+ message:messagePrefix
pithosAccount:pithosAccount];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility updateActivity:activity withMessage:activity.message];
pithosContainer, @"pithosContainer",
object, @"pithosObject",
messagePrefix, @"messagePrefix",
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, (NSUInteger)ceil((object.bytes +0.0)/(pithosContainer.blockSize + 0.0)))], @"missingBlocks",
- [NSNumber numberWithUnsignedInteger:0], @"missingBlockIndex",
- filePath, @"filePath",
activity, @"activity",
[messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
[messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
- [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
- [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
- NSStringFromSelector(@selector(downloadObjectBlockFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector",
NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
nil];
- [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
- [activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
- messagePrefix, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
- totalBytes:activity.totalBytes
- currentBytes:(activity.currentBytes + size)];
- }];
- [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]];
- }
- } else {
- // Resume local object download
- if (!remoteObjectExists || remoteIsDirectory) {
- // Remote file object deleted or changed to a directory object in the meantime, mark the sync cycle as incomplete and skip
- syncIncomplete = YES;
- [pool drain];
- return;
- }
- // Create directory of the file, if it doesn't exist
- error = nil;
- if (![PithosUtilities safeCreateDirectory:fileDirectoryPath error:&error]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
- message:[NSString stringWithFormat:@"Cannot create directory at '%@'", fileDirectoryPath]
- error:error];
- });
- }
- // Check first if a local copy exists
- if ([self findLocalCopyForObjectWithHash:object.objectHash forFile:filePath]) {
- storedState.filePath = filePath;
- storedState.hash = object.objectHash;
- // Delete incomplete temp download
- storedState.tmpFilePath = nil;
- [self saveLocalState];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name],
- object.name]
- pithosAccount:pithosAccount];
- });
- } else {
- [self syncOperationStarted];
- ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectHashmapRequestWithPithos:pithos
- containerName:pithosContainer.name
- objectName:object.name];
- if (![accountName isEqualToString:@""])
- [objectRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Downloading '%@/%@'",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload
- message:[messagePrefix stringByAppendingString:@" (0%%)"]
- totalBytes:object.bytes
- currentBytes:0
- pithosAccount:pithosAccount];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity withMessage:activity.message];
- });
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- accountName, @"accountName",
- pithosContainer, @"pithosContainer",
- object, @"pithosObject",
- messagePrefix, @"messagePrefix",
- filePath, @"filePath",
- activity, @"activity",
- [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
- [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
- [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
- [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
- [NSNumber numberWithUnsignedInteger:10], @"retries",
- NSStringFromSelector(@selector(downloadObjectHashMapFinished:)), @"didFinishSelector",
- NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
- nil];
- [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]];
- }
- }
- [pool drain];
-}
-
--(void)updateServerStateWithCurrentState:(PithosLocalObjectState *)currentState
- object:(ASIPithosObject *)object
- localFilePath:(NSString *)filePath
- accountName:(NSString *)accountName
- pithosContainer:(ASIPithosContainer *)pithosContainer {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [self syncOperationStarted];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- BOOL isDirectory;
- BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
- if (currentState.isDirectory) {
- // Create remote directory object
- if (![accountName isEqualToString:@""]) {
- if (!object.allowedTo) {
- NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
- NSString *objectAncestorName = [object.name stringByDeletingLastPathComponent];
- while ([objectAncestorName length] && !object.allowedTo) {
- object.allowedTo = [[containerRemoteObjects objectForKey:objectAncestorName] allowedTo];
- objectAncestorName = [objectAncestorName stringByDeletingLastPathComponent];
- }
- }
- if (![object.allowedTo isEqualToString:@"write"]) {
- // If read-only "shared to me" skip
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ } else if (![currentState exists]) {
+ // Delete remote object
+ if (![accountName isEqualToString:@""]) {
+ // If "shared with me" skip
[self syncOperationFinishedWithSuccess:YES];
- [pool drain];
return;
}
- }
- if (!fileExists || !isDirectory) {
- // Local directory object deleted or changed to a file in the meantime, mark the sync cycle as incomplete and skip
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
- ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos
+ if (fileExists) {
+ // Local object created in the meantime, just mark the sync cycle as incomplete, but do delete the server object
+ syncIncomplete = YES;
+ }
+ if ([pithosContainer.name isEqualToString:@"trash"]) {
+ // Delete
+ ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Deleting '%@/%@'",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete
+ message:messagePrefix
+ pithosAccount:pithosAccount];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity withMessage:activity.message];
+ });
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ accountName, @"accountName",
+ pithosContainer, @"pithosContainer",
+ object, @"pithosObject",
+ messagePrefix, @"messagePrefix",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(deleteObjectFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ nil];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ } else {
+ // Move to container trash
+ NSString *safeName;
+ if ([PithosUtilities isContentTypeDirectory:object.contentType])
+ safeName = [PithosUtilities safeSubdirNameForPithos:pithos containerName:@"trash" subdirName:object.name];
+ else
+ safeName = [PithosUtilities safeObjectNameForPithos:pithos containerName:@"trash" objectName:object.name];
+ if (safeName) {
+ ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos
containerName:pithosContainer.name
objectName:object.name
- eTag:nil
- contentType:@"application/directory"
- contentEncoding:nil
- contentDisposition:nil
- manifest:nil
- sharing:nil
- isPublic:ASIPithosObjectRequestPublicIgnore
- metadata:nil
- data:[NSData data]];
- if (![accountName isEqualToString:@""])
- [objectRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Creating directory '%@/%@'",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory
- message:messagePrefix
- pithosAccount:pithosAccount];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity withMessage:activity.message];
- });
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- accountName, @"accountName",
- pithosContainer, @"pithosContainer",
- object, @"pithosObject",
- messagePrefix, @"messagePrefix",
- activity, @"activity",
- [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
- [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
- [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
- [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
- [NSNumber numberWithUnsignedInteger:10], @"retries",
- NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector",
- NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
- nil];
- [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
- } else if (![currentState exists]) {
- // Delete remote object
- if (![accountName isEqualToString:@""]) {
- // If "shared to me" skip
- [self syncOperationFinishedWithSuccess:YES];
- [pool drain];
- return;
- }
- if (fileExists) {
- // Local object created in the meantime, just mark the sync cycle as incomplete, but do delete the server object
- syncIncomplete = YES;
- }
- if ([pithosContainer.name isEqualToString:@"trash"]) {
- // Delete
- ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithPithos:pithos
- containerName:pithosContainer.name
- objectName:object.name];
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Deleting '%@/%@'",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete
- message:messagePrefix
- pithosAccount:pithosAccount];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity withMessage:activity.message];
- });
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- accountName, @"accountName",
- pithosContainer, @"pithosContainer",
- object, @"pithosObject",
- messagePrefix, @"messagePrefix",
- activity, @"activity",
- [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
- [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
- [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
- [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
- [NSNumber numberWithUnsignedInteger:10], @"retries",
- NSStringFromSelector(@selector(deleteObjectFinished:)), @"didFinishSelector",
- NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
- nil];
- [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
- } else {
- // Move to container trash
- NSString *safeName;
- if ([PithosUtilities isContentTypeDirectory:object.contentType])
- safeName = [PithosUtilities safeSubdirNameForPithos:pithos containerName:@"trash" subdirName:object.name];
- else
- safeName = [PithosUtilities safeObjectNameForPithos:pithos containerName:@"trash" objectName:object.name];
- if (safeName) {
- ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos
- containerName:pithosContainer.name
- objectName:object.name
- destinationContainerName:@"trash"
- destinationObjectName:safeName
- checkIfExists:NO];
- if (objectRequest) {
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@'",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete
- message:messagePrefix
- pithosAccount:pithosAccount];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity withMessage:activity.message];
- });
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- accountName, @"accountName",
- pithosContainer, @"pithosContainer",
- object, @"pithosObject",
- messagePrefix, @"messagePrefix",
- activity, @"activity",
- [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
- [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
- [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
- [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
- [NSNumber numberWithUnsignedInteger:10], @"retries",
- NSStringFromSelector(@selector(moveObjectToTrashFinished:)), @"didFinishSelector",
- NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
- nil];
- [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ destinationContainerName:@"trash"
+ destinationObjectName:safeName
+ checkIfExists:NO];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@'",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete
+ message:messagePrefix
+ pithosAccount:pithosAccount];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity withMessage:activity.message];
+ });
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ accountName, @"accountName",
+ pithosContainer, @"pithosContainer",
+ object, @"pithosObject",
+ messagePrefix, @"messagePrefix",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(moveObjectToTrashFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ nil];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ } else {
+ [self syncOperationFinishedWithSuccess:NO];
+ }
} else {
[self syncOperationFinishedWithSuccess:NO];
}
- } else {
- [self syncOperationFinishedWithSuccess:NO];
}
- }
- } else {
- // Upload file to remote object
- if (![accountName isEqualToString:@""]) {
- if (!object.allowedTo) {
- NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
- NSString *objectAncestorName = [object.name stringByDeletingLastPathComponent];
- while ([objectAncestorName length] && !object.allowedTo) {
- object.allowedTo = [[containerRemoteObjects objectForKey:objectAncestorName] allowedTo];
- objectAncestorName = [objectAncestorName stringByDeletingLastPathComponent];
+ } else {
+ // Upload file to remote object
+ if (![accountName isEqualToString:@""]) {
+ if (!object.allowedTo) {
+ NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
+ NSString *objectAncestorName = [object.name stringByDeletingLastPathComponent];
+ while ([objectAncestorName length] && !object.allowedTo) {
+ object.allowedTo = [[containerRemoteObjects objectForKey:objectAncestorName] allowedTo];
+ objectAncestorName = [objectAncestorName stringByDeletingLastPathComponent];
+ }
+ }
+ if (![object.allowedTo isEqualToString:@"write"]) {
+ // If read-only "shared with me" skip
+ [self syncOperationFinishedWithSuccess:YES];
+ return;
}
}
- if (![object.allowedTo isEqualToString:@"write"]) {
- // If read-only "shared to me" skip
- [self syncOperationFinishedWithSuccess:YES];
- [pool drain];
+ if (!fileExists || isDirectory) {
+ // Local file object deleted or changed to a directory in the meantime, mark the sync cycle as incomplete and skip
+ [self syncOperationFinishedWithSuccess:NO];
return;
}
- }
- if (!fileExists || isDirectory) {
- // Local file object deleted or changed to a directory in the meantime, mark the sync cycle as incomplete and skip
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
- NSError *error = nil;
- object.contentType = [PithosUtilities contentTypeOfFile:filePath error:&error];
- if (object.contentType == nil)
- object.contentType = @"application/octet-stream";
- if (error)
- NSLog(@"contentType detection error: %@", error);
- NSArray *hashes = nil;
- ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos
- containerName:pithosContainer.name
- objectName:object.name
- contentType:object.contentType
- blockSize:pithosContainer.blockSize
- blockHash:pithosContainer.blockHash
- forFile:filePath
- checkIfExists:NO
- hashes:&hashes
- sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
- if (objectRequest) {
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Uploading '%@/%@'",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload
- message:[messagePrefix stringByAppendingString:@" (0%%)"]
- totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
- currentBytes:0
- pithosAccount:pithosAccount];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity withMessage:activity.message];
- });
- [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
- [NSDictionary dictionaryWithObjectsAndKeys:
- accountName, @"accountName",
- pithosContainer, @"pithosContainer",
- object, @"pithosObject",
- messagePrefix, @"messagePrefix",
- filePath, @"filePath",
- hashes, @"hashes",
- [NSNumber numberWithUnsignedInteger:10], @"iteration",
- activity, @"activity",
- [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
- [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
- [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
- [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
- [NSNumber numberWithUnsignedInteger:10], @"retries",
- NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector",
- NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
- nil]];
- [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]];
- } else {
- [self syncOperationFinishedWithSuccess:NO];
+ NSError *error = nil;
+ object.contentType = [PithosUtilities contentTypeOfFile:filePath error:&error];
+ if (object.contentType == nil)
+ object.contentType = @"application/octet-stream";
+ #if DEBUG_PITHOS
+ if (error)
+ DLog(@"contentType detection error: %@", error);
+ #endif
+ NSArray *hashes = nil;
+ ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name
+ contentType:object.contentType
+ blockSize:pithosContainer.blockSize
+ blockHash:pithosContainer.blockHash
+ forFile:filePath
+ checkIfExists:NO
+ hashes:&hashes
+ sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Sync: Uploading '%@/%@'",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload
+ message:[messagePrefix stringByAppendingString:@" (0%%)"]
+ totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
+ currentBytes:0
+ pithosAccount:pithosAccount];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity withMessage:activity.message];
+ });
+ [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ accountName, @"accountName",
+ pithosContainer, @"pithosContainer",
+ object, @"pithosObject",
+ messagePrefix, @"messagePrefix",
+ filePath, @"filePath",
+ hashes, @"hashes",
+ [NSNumber numberWithUnsignedInteger:10], @"iteration",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ nil]];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]];
+ } else {
+ [self syncOperationFinishedWithSuccess:NO];
+ }
}
}
- [pool drain];
}
#pragma mark -
- (void)performRequestFinishedDelegateInBackground:(ASIPithosRequest *)request {
// Add an operation to the callbackQueue with a completionBlock for the case of cancellation
- NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self
+ NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:NSSelectorFromString([request.userInfo objectForKey:@"didFinishSelector"])
- object:request] autorelease];
+ object:request];
operation.completionBlock = ^{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
- withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:NO];
+ @autoreleasepool {
+ if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
+ withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ }
}
- [pool drain];
};
[(NSMutableDictionary *)request.userInfo setObject:operation forKey:@"operation"];
[callbackQueue addOperation:operation];
withObject:request];
} else {
// Add an operation to the callbackQueue with a completionBlock for the case of cancellation
- NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self
+ NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:NSSelectorFromString([request.userInfo objectForKey:@"didFailSelector"])
- object:request] autorelease];
+ object:request];
operation.completionBlock = ^{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
- withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:NO];
+ @autoreleasepool {
+ if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
+ withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ }
}
- [pool drain];
};
[(NSMutableDictionary *)request.userInfo setObject:operation forKey:@"operation"];
[callbackQueue addOperation:operation];
}
- (void)listRequestFinished:(ASIPithosContainerRequest *)containerRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [containerRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::list request finished: %@", containerRequest.url);
- if (operation.isCancelled) {
- [self listRequestFailed:containerRequest];
- } else if ((containerRequest.responseStatusCode == 200) ||
- (containerRequest.responseStatusCode == 304) ||
- (containerRequest.responseStatusCode == 403)) {
- NSString *accountName = [accountsNames objectAtIndex:accountsIndex];
- ASIPithosContainer *pithosContainer = [[accountsPithosContainers objectForKey:accountName] objectAtIndex:containersIndex];
- if (containerRequest.responseStatusCode == 200) {
- NSArray *someObjects = [containerRequest objects];
- if (objects == nil) {
- objects = [[NSMutableArray alloc] initWithArray:someObjects];
- } else {
- [objects addObjectsFromArray:someObjects];
- }
- if ([someObjects count] < 10000) {
- pithosContainer.blockHash = [containerRequest blockHash];
- pithosContainer.blockSize = [containerRequest blockSize];
- pithosContainer.lastModified = [containerRequest lastModified];
- NSMutableDictionary *containerRemoteObjects = [NSMutableDictionary dictionaryWithCapacity:[objects count]];
- for (ASIPithosObject *object in objects) {
- [containerRemoteObjects setObject:object forKey:object.name];
+ @autoreleasepool {
+ NSOperation *operation = [containerRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::list request finished: %@", containerRequest.url);
+ if (operation.isCancelled) {
+ [self listRequestFailed:containerRequest];
+ } else if ((containerRequest.responseStatusCode == 200) ||
+ (containerRequest.responseStatusCode == 304) ||
+ (containerRequest.responseStatusCode == 403)) {
+ NSString *accountName = [accountsNames objectAtIndex:accountsIndex];
+ ASIPithosContainer *pithosContainer = [[accountsPithosContainers objectForKey:accountName] objectAtIndex:containersIndex];
+ if (containerRequest.responseStatusCode == 200) {
+ NSArray *someObjects = [containerRequest objects];
+ if (objects == nil) {
+ objects = [[NSMutableArray alloc] initWithArray:someObjects];
+ } else {
+ [objects addObjectsFromArray:someObjects];
}
- [[remoteObjects objectForKey:accountName] setObject:containerRemoteObjects forKey:pithosContainer.name];
- [objects release];
- objects = nil;
- } else {
- // Do an additional request to fetch more objects
+ if ([someObjects count] < 10000) {
+ pithosContainer.blockHash = [containerRequest blockHash];
+ pithosContainer.blockSize = [containerRequest blockSize];
+ pithosContainer.lastModified = [containerRequest lastModified];
+ NSMutableDictionary *containerRemoteObjects = [NSMutableDictionary dictionaryWithCapacity:[objects count]];
+ for (ASIPithosObject *object in objects) {
+ [containerRemoteObjects setObject:object forKey:object.name];
+ }
+ [[remoteObjects objectForKey:accountName] setObject:containerRemoteObjects forKey:pithosContainer.name];
+ objects = nil;
+ } else {
+ // Do an additional request to fetch more objects
+ ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ limit:0
+ marker:[[someObjects lastObject] name]
+ prefix:nil
+ delimiter:nil
+ path:nil
+ meta:nil
+ shared:NO
+ until:nil
+ ifModifiedSince:pithosContainer.lastModified];
+ if (![accountName isEqualToString:@""])
+ [newContainerRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
+ newContainerRequest.delegate = self;
+ newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ newContainerRequest.userInfo = containerRequest.userInfo;
+ [(NSMutableDictionary *)newContainerRequest.userInfo setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ return;
+ }
+ } else if (containerRequest.responseStatusCode == 304) {
+ NSMutableDictionary *containerRemoteObjects = [[previousRemoteObjects objectForKey:accountName]
+ objectForKey:pithosContainer.name];
+ if (containerRemoteObjects)
+ [[remoteObjects objectForKey:accountName] setObject:containerRemoteObjects forKey:pithosContainer.name];
+ } else if (containerRequest.responseStatusCode == 403) {
+ [[remoteObjects objectForKey:accountName] setObject:[NSMutableDictionary dictionary] forKey:pithosContainer.name];
+ }
+
+ containersIndex++;
+ if (containersIndex == [[accountsPithosContainers objectForKey:accountName] count]) {
+ accountsIndex++;
+ containersIndex = 0;
+ }
+ if (accountsIndex < accountsCount) {
+ accountName = [accountsNames objectAtIndex:accountsIndex];
+ pithosContainer = [[accountsPithosContainers objectForKey:accountName] objectAtIndex:containersIndex];
+ // Do a request for the next container
ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
containerName:pithosContainer.name
limit:0
- marker:[[someObjects lastObject] name]
+ marker:nil
prefix:nil
delimiter:nil
path:nil
newContainerRequest.userInfo = containerRequest.userInfo;
[(NSMutableDictionary *)newContainerRequest.userInfo setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
[networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
- [pool drain];
return;
}
- } else if (containerRequest.responseStatusCode == 304) {
- NSMutableDictionary *containerRemoteObjects = [[previousRemoteObjects objectForKey:accountName]
- objectForKey:pithosContainer.name];
- if (containerRemoteObjects)
- [[remoteObjects objectForKey:accountName] setObject:containerRemoteObjects forKey:pithosContainer.name];
- } else if (containerRequest.responseStatusCode == 403) {
- [[remoteObjects objectForKey:accountName] setObject:[NSMutableDictionary dictionary] forKey:pithosContainer.name];
- }
-
- containersIndex++;
- if (containersIndex == [[accountsPithosContainers objectForKey:accountName] count]) {
- accountsIndex++;
- containersIndex = 0;
- }
- if (accountsIndex < accountsCount) {
- accountName = [accountsNames objectAtIndex:accountsIndex];
- pithosContainer = [[accountsPithosContainers objectForKey:accountName] objectAtIndex:containersIndex];
- // Do a request for the next container
- ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
- containerName:pithosContainer.name
- limit:0
- marker:nil
- prefix:nil
- delimiter:nil
- path:nil
- meta:nil
- shared:NO
- until:nil
- ifModifiedSince:pithosContainer.lastModified];
- if (![accountName isEqualToString:@""])
- [newContainerRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
- newContainerRequest.delegate = self;
- newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- newContainerRequest.userInfo = containerRequest.userInfo;
- [(NSMutableDictionary *)newContainerRequest.userInfo setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
- [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
- [pool drain];
- return;
- }
- self.previousRemoteObjects = remoteObjects;
- // remoteObjects contains all remote objects for the legal containers, without enforcing directory exclusions
-
- if (operation.isCancelled) {
- [self listRequestFailed:containerRequest];
- [pool drain];
- return;
- }
+ self.previousRemoteObjects = remoteObjects;
+ // remoteObjects contains all remote objects for the legal containers, without enforcing directory exclusions
+
+ if (operation.isCancelled) {
+ [self listRequestFailed:containerRequest];
+ return;
+ }
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"]
- withMessage:[containerRequest.userInfo objectForKey:@"finishedActivityMessage"]];
- });
- NSFileManager *fileManager = [NSFileManager defaultManager];
-
- // Compute current state of legal existing local objects
- // and add an empty stored state for legal new local objects since last sync
- self.currentLocalObjectStates = [NSMutableDictionary dictionary];
- for (NSString *accountName in accountsNames) {
- for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
- NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
- NSSet *containerExcludedDirectories = [[accountsDictionary objectForKey:accountName] objectForKey:pithosContainer.name];
- BOOL containerExludeRootFiles = [containerExcludedDirectories containsObject:@""];
- NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
- objectForKey:pithosContainer.name];
- NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:containerDirectoryPath];
- for (NSString *objectName in dirEnumerator) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self saveLocalState];
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"]
+ withMessage:[containerRequest.userInfo objectForKey:@"finishedActivityMessage"]];
+ });
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+
+ // Compute current state of legal existing local objects
+ // and add an empty stored state for legal new local objects since last sync
+ self.currentLocalObjectStates = [NSMutableDictionary dictionary];
+ for (NSString *accountName in accountsNames) {
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
+ NSSet *containerExcludedDirectories = [[accountsDictionary objectForKey:accountName] objectForKey:pithosContainer.name];
+ BOOL containerExcludeRootFiles = [containerExcludedDirectories containsObject:@""];
+ NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name];
+ NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:containerDirectoryPath];
+ for (__strong NSString *objectName in dirEnumerator) {
+ objectName = [objectName precomposedStringWithCanonicalMapping];
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self saveLocalState];
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
- NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
- NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
- BOOL isDirectory;
- BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
- if ([[attributes fileType] isEqualToString:NSFileTypeSymbolicLink]) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
+ NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
+ BOOL isDirectory;
+ BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
+ if ([[attributes fileType] isEqualToString:NSFileTypeSymbolicLink]) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Sync Error"
message:[NSString stringWithFormat:@"Sync directory at '%@' contains symbolic links. Remove them and re-activate sync for account '%@'.",
containerDirectoryPath, pithosAccount.name]
error:nil];
- });
- pithosAccount.syncActive = NO;
- return;
- } else if (fileExists) {
- NSArray *pathComponents = [objectName pathComponents];
- if ([pathComponents count] == 1) {
- if ([containerExcludedDirectories containsObject:[objectName lowercaseString]]) {
- // Skip excluded directory and its descendants, or root file with same name
+ pithosAccount.syncActive = NO;
+ return;
+ } else if (fileExists) {
+ if (skipHidden && [[objectName lastPathComponent] hasPrefix:@"."]) {
+ // Skip hidden directory and its descendants, or hidden file
if (isDirectory)
[dirEnumerator skipDescendants];
// Remove stored state if any
[containerStoredLocalObjectStates removeObjectForKey:objectName];
continue;
- } else if (!isDirectory && containerExludeRootFiles) {
- // Skip excluded root file
- // Remove stored state if any
- [containerStoredLocalObjectStates removeObjectForKey:objectName];
- continue;
+ } else if ([[objectName pathComponents] count] == 1) {
+ if ([containerExcludedDirectories containsObject:[objectName lowercaseString]]) {
+ // Skip excluded directory and its descendants, or root file with same name
+ if (isDirectory)
+ [dirEnumerator skipDescendants];
+ // Remove stored state if any
+ [containerStoredLocalObjectStates removeObjectForKey:objectName];
+ continue;
+ } else if (!isDirectory && containerExcludeRootFiles) {
+ // Skip excluded root file
+ // Remove stored state if any
+ [containerStoredLocalObjectStates removeObjectForKey:objectName];
+ continue;
+ }
+ }
+ // Include local object
+ PithosLocalObjectState *storedLocalObjectState = [containerStoredLocalObjectStates objectForKey:objectName];
+ if (!storedLocalObjectState || [storedLocalObjectState isModified]) {
+ // New or modified existing local object, compute current state
+ if (!storedLocalObjectState)
+ // For new local object, also create empty stored state
+ [containerStoredLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:objectName];
+ [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:filePath
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize]
+ forKey:filePath];
+ } else {
+ // Local object hasn't changed, set stored state also to current
+ [currentLocalObjectStates setObject:storedLocalObjectState forKey:filePath];
}
- }
- // Include local object
- PithosLocalObjectState *storedLocalObjectState = [containerStoredLocalObjectStates objectForKey:objectName];
- if (!storedLocalObjectState || [storedLocalObjectState isModified]) {
- // New or modified existing local object, compute current state
- if (!storedLocalObjectState)
- // For new local object, also create empty stored state
- [containerStoredLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:objectName];
- [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:filePath
- blockHash:pithosContainer.blockHash
- blockSize:pithosContainer.blockSize]
- forKey:filePath];
- } else {
- // Local object hasn't changed, set stored state also to current
- [currentLocalObjectStates setObject:storedLocalObjectState forKey:filePath];
}
}
+ [self saveLocalState];
}
- [self saveLocalState];
}
- }
-
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
-
- // Add an empty stored state for legal new remote objects since last sync
- for (NSString *accountName in accountsNames) {
- for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
- NSSet *containerExcludedDirectories = [[accountsDictionary objectForKey:accountName] objectForKey:pithosContainer.name];
- BOOL containerExludeRootFiles = [containerExcludedDirectories containsObject:@""];
- NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
- objectForKey:pithosContainer.name];
- NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
- for (NSString *objectName in containerRemoteObjects) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self saveLocalState];
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
-
- ASIPithosObject *object = [containerRemoteObjects objectForKey:objectName];
- NSString *localObjectName;
- if ([object.name hasSuffix:@"/"])
- localObjectName = [NSString stringWithFormat:@"%@:", [object.name substringToIndex:([object.name length] -1)]];
- else
- localObjectName = [NSString stringWithString:object.name];
- NSArray *pathComponents = [localObjectName pathComponents];
- if ([containerExcludedDirectories containsObject:[[pathComponents objectAtIndex:0] lowercaseString]]) {
- // Skip excluded directory object and its descendants, or root file object with same name
- // Remove stored state if any
- [containerStoredLocalObjectStates removeObjectForKey:object.name];
- continue;
- } else if (containerExludeRootFiles &&
- ([pathComponents count] == 1) &&
- ![PithosUtilities isContentTypeDirectory:object.contentType]) {
- // Skip root file object
- // Remove stored state if any
- [containerStoredLocalObjectStates removeObjectForKey:object.name];
- continue;
- }
- if (![containerStoredLocalObjectStates objectForKey:object.name])
- [containerStoredLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:object.name];
- }
- [self saveLocalState];
+
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
}
- }
-
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
- // For each stored state compare with current and remote state
- // Stored states of local objects that have been deleted,
- // haven't been checked for legality (only existing local remote objects)
- // These should be identified and skipped
- for (NSString *accountName in accountsNames) {
- for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
- NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
- NSSet *containerExcludedDirectories = [[accountsDictionary objectForKey:accountName] objectForKey:pithosContainer.name];
- BOOL containerExludeRootFiles = [containerExcludedDirectories containsObject:@""];
- NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
- objectForKey:pithosContainer.name];
- NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
- for (NSString *objectName in [[containerStoredLocalObjectStates allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ // Add an empty stored state for legal new remote objects since last sync
+ for (NSString *accountName in accountsNames) {
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ NSSet *containerExcludedDirectories = [[accountsDictionary objectForKey:accountName] objectForKey:pithosContainer.name];
+ BOOL containerExcludeRootFiles = [containerExcludedDirectories containsObject:@""];
+ NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name];
+ NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
+ for (NSString *objectName in containerRemoteObjects) {
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self saveLocalState];
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
- NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
- if ([objectName hasSuffix:@"/"])
- filePath = [filePath stringByAppendingString:@":"];
- ASIPithosObject *object = [ASIPithosObject object];
- object.name = objectName;
- NSLog(@"Sync::object name: %@", object.name);
-
- PithosLocalObjectState *storedLocalObjectState = [containerStoredLocalObjectStates objectForKey:object.name];
- PithosLocalObjectState *currentLocalObjectState = [currentLocalObjectStates objectForKey:filePath];
- if (!currentLocalObjectState) {
- // The stored state corresponds to a remote or deleted local object, that's why there is no current state
- // In the latter case it must be checked for legality, which can be determined by its stored state
- // If it existed locally, but was deleted, state.exists is true,
- // else if the stored state is an empty state that was created due to the server object, state.exists is false
- if (storedLocalObjectState.exists) {
- NSString *localObjectName;
- if ([object.name hasSuffix:@"/"])
- localObjectName = [NSString stringWithFormat:@"%@:", [object.name substringToIndex:([object.name length] -1)]];
- else
- localObjectName = [NSString stringWithString:object.name];
- NSArray *pathComponents = [localObjectName pathComponents];
- if ([containerExcludedDirectories containsObject:[[pathComponents objectAtIndex:0] lowercaseString]]) {
- // Skip excluded directory object and its descendants, or root file object with same name
- // Remove stored state
- [containerStoredLocalObjectStates removeObjectForKey:object.name];
- [self saveLocalState];
- continue;
- } else if (containerExludeRootFiles && ([pathComponents count] == 1) && !storedLocalObjectState.isDirectory) {
- // Skip root file object
- // Remove stored state
- [containerStoredLocalObjectStates removeObjectForKey:object.name];
- [self saveLocalState];
- continue;
+ ASIPithosObject *object = [containerRemoteObjects objectForKey:objectName];
+ NSString *localObjectName;
+ if ([object.name hasSuffix:@"/"])
+ localObjectName = [NSString stringWithFormat:@"%@:", [object.name substringToIndex:([object.name length] -1)]];
+ else
+ localObjectName = [NSString stringWithString:object.name];
+ NSArray *pathComponents = [localObjectName pathComponents];
+ if (skipHidden) {
+ BOOL skipObject = NO;
+ for (NSString *pathComponent in pathComponents) {
+ if ([pathComponent hasPrefix:@"."]) {
+ // Skip hidden directory and its descendants, or hidden file
+ // Remove stored state if any
+ [containerStoredLocalObjectStates removeObjectForKey:objectName];
+ skipObject = YES;
+ break;
+ }
}
+ if (skipObject)
+ continue;
}
- // There is also the off case that a local object has been created in the meantime
- // This call works in any case, existent or non-existent local object
- currentLocalObjectState = [PithosLocalObjectState localObjectStateWithFile:filePath
- blockHash:pithosContainer.blockHash
- blockSize:pithosContainer.blockSize];
- }
-
- PithosLocalObjectState *remoteObjectState = [PithosLocalObjectState localObjectState];
- ASIPithosObject *remoteObject = [containerRemoteObjects objectForKey:object.name];
- if (remoteObject) {
- if ([PithosUtilities isContentTypeDirectory:remoteObject.contentType]) {
- remoteObjectState.isDirectory = YES;
- } else {
- remoteObjectState.hash = remoteObject.objectHash;
+ if ([containerExcludedDirectories containsObject:[[pathComponents objectAtIndex:0] lowercaseString]]) {
+ // Skip excluded directory object and its descendants, or root file object with same name
+ // Remove stored state if any
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
+ continue;
+ } else if (containerExcludeRootFiles &&
+ ([pathComponents count] == 1) &&
+ ![PithosUtilities isContentTypeDirectory:object.contentType]) {
+ // Skip root file object
+ // Remove stored state if any
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
+ continue;
}
+ if (![containerStoredLocalObjectStates objectForKey:object.name])
+ [containerStoredLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:object.name];
}
+ [self saveLocalState];
+ }
+ }
- BOOL localStateHasChanged = ![currentLocalObjectState isEqualToState:storedLocalObjectState];
- BOOL serverStateHasChanged = ![remoteObjectState isEqualToState:storedLocalObjectState];
- NSLog(@"Sync::localStateHasChanged: %d, serverStateHasChanged: %d", localStateHasChanged, serverStateHasChanged);
- if (!localStateHasChanged) {
- // Local state hasn't changed
- if (serverStateHasChanged) {
- // Server state has changed
- // Update local state to match that of the server
- object.bytes = remoteObject.bytes;
- object.version = remoteObject.version;
- object.contentType = remoteObject.contentType;
- object.objectHash = remoteObject.objectHash;
- [self updateLocalStateWithObject:object localFilePath:filePath
- accountName:accountName pithosContainer:pithosContainer];
- } else if (!remoteObject && ![currentLocalObjectState exists]) {
- // Server state hasn't changed
- // If the object doesn't exist neither in the server or locally, it should be removed from the stored local objects
- [containerStoredLocalObjectStates removeObjectForKey:objectName];
- [self saveLocalState];
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+
+ // For each stored state compare with current and remote state
+ // Stored states of local objects that have been deleted,
+ // haven't been checked for legality (only existing local remote objects)
+ // These should be identified and skipped
+ for (NSString *accountName in accountsNames) {
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
+ NSSet *containerExcludedDirectories = [[accountsDictionary objectForKey:accountName] objectForKey:pithosContainer.name];
+ BOOL containerExcludeRootFiles = [containerExcludedDirectories containsObject:@""];
+ NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name];
+ NSMutableDictionary *containerRemoteObjects = [[remoteObjects objectForKey:accountName] objectForKey:pithosContainer.name];
+ for (NSString *objectName in [[containerStoredLocalObjectStates allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
}
- } else {
- // Local state has changed
- if (!serverStateHasChanged) {
- // Server state hasn't changed
- if (currentLocalObjectState.isDirectory)
- object.contentType = @"application/directory";
- else
- object.objectHash = currentLocalObjectState.hash;
- [self updateServerStateWithCurrentState:currentLocalObjectState object:object localFilePath:filePath
- accountName:accountName pithosContainer:pithosContainer];
- } else {
- // Server state has also changed
- if (remoteObjectState.isDirectory && currentLocalObjectState.isDirectory) {
- // Both did the same change (directory)
- storedLocalObjectState.filePath = filePath;
- storedLocalObjectState.isDirectory = YES;
- [self saveLocalState];
- } else if ([remoteObjectState isEqualToState:currentLocalObjectState]) {
- // Both did the same change (object edit or delete)
- if (![remoteObjectState exists]) {
- [containerStoredLocalObjectStates removeObjectForKey:object.name];
- } else {
- storedLocalObjectState.filePath = filePath;
- storedLocalObjectState.hash = remoteObjectState.hash;
+
+ NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
+ if ([objectName hasSuffix:@"/"])
+ filePath = [filePath stringByAppendingString:@":"];
+ ASIPithosObject *object = [ASIPithosObject object];
+ object.name = objectName;
+ DLog(@"Sync::object name: %@", object.name);
+
+ PithosLocalObjectState *storedLocalObjectState = [containerStoredLocalObjectStates objectForKey:object.name];
+ PithosLocalObjectState *currentLocalObjectState = [currentLocalObjectStates objectForKey:filePath];
+ if (!currentLocalObjectState) {
+ // The stored state corresponds to a remote or deleted local object, that's why there is no current state
+ // In the latter case it must be checked for legality, which can be determined by its stored state
+ // If it existed locally, but was deleted, state.exists is true,
+ // else if the stored state is an empty state that was created due to the server object, state.exists is false
+ if (storedLocalObjectState.exists) {
+ NSString *localObjectName;
+ if ([object.name hasSuffix:@"/"])
+ localObjectName = [NSString stringWithFormat:@"%@:", [object.name substringToIndex:([object.name length] -1)]];
+ else
+ localObjectName = [NSString stringWithString:object.name];
+ NSArray *pathComponents = [localObjectName pathComponents];
+ if (skipHidden) {
+ BOOL skipObject = NO;
+ for (NSString *pathComponent in pathComponents) {
+ if ([pathComponent hasPrefix:@"."]) {
+ // Skip hidden directory and its descendants, or hidden file
+ // Remove stored state if any
+ [containerStoredLocalObjectStates removeObjectForKey:objectName];
+ [self saveLocalState];
+ skipObject = YES;
+ break;
+ }
+ }
+ if (skipObject)
+ continue;
+ }
+ if ([containerExcludedDirectories containsObject:[[pathComponents objectAtIndex:0] lowercaseString]]) {
+ // Skip excluded directory object and its descendants, or root file object with same name
+ // Remove stored state
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
+ [self saveLocalState];
+ continue;
+ } else if (containerExcludeRootFiles && ([pathComponents count] == 1) && !storedLocalObjectState.isDirectory) {
+ // Skip root file object
+ // Remove stored state
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
+ [self saveLocalState];
+ continue;
+ }
}
- [self saveLocalState];
- } else {
- // Conflict, we ask the user which change to keep
- NSString *informativeText;
- NSString *firstButtonText;
- NSString *secondButtonText;
-
- if (![remoteObjectState exists]) {
- // Remote object has been deleted
- informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified locally, while it has been deleted from server.",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name ];
- firstButtonText = @"Delete local file";
- secondButtonText = @"Upload file to server";
- } else if (![currentLocalObjectState exists]) {
- informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified on the server, while it has been deleted locally.",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- firstButtonText = @"Download file from server";
- secondButtonText = @"Delete file on server";
+ // There is also the off case that a local object has been created in the meantime
+ // This call works in any case, existent or non-existent local object
+ currentLocalObjectState = [PithosLocalObjectState localObjectStateWithFile:filePath
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize];
+ }
+
+ PithosLocalObjectState *remoteObjectState = [PithosLocalObjectState localObjectState];
+ ASIPithosObject *remoteObject = [containerRemoteObjects objectForKey:object.name];
+ if (remoteObject) {
+ if ([PithosUtilities isContentTypeDirectory:remoteObject.contentType]) {
+ remoteObjectState.isDirectory = YES;
} else {
- informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified both locally and on the server.",
- [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
- firstButtonText = @"Keep server version";
- secondButtonText = @"Keep local version";
+ remoteObjectState.hash = remoteObject.objectHash;
}
- NSAlert *alert = [[[NSAlert alloc] init] autorelease];
- [alert setMessageText:@"Conflict"];
- [alert setInformativeText:informativeText];
- [alert addButtonWithTitle:firstButtonText];
- [alert addButtonWithTitle:secondButtonText];
- [alert addButtonWithTitle:@"Do nothing"];
- NSInteger choice = [alert runModal];
- if (choice == NSAlertFirstButtonReturn) {
+ }
+
+ BOOL localStateHasChanged = ![currentLocalObjectState isEqualToState:storedLocalObjectState];
+ BOOL serverStateHasChanged = ![remoteObjectState isEqualToState:storedLocalObjectState];
+ DLog(@"Sync::localStateHasChanged: %d, serverStateHasChanged: %d", localStateHasChanged, serverStateHasChanged);
+ if (!localStateHasChanged) {
+ // Local state hasn't changed
+ if (serverStateHasChanged) {
+ // Server state has changed
+ // Update local state to match that of the server
object.bytes = remoteObject.bytes;
object.version = remoteObject.version;
object.contentType = remoteObject.contentType;
object.objectHash = remoteObject.objectHash;
[self updateLocalStateWithObject:object localFilePath:filePath
- accountName:accountName pithosContainer:pithosContainer];
- } if (choice == NSAlertSecondButtonReturn) {
- if (currentLocalObjectState.isDirectory)
- object.contentType = @"application/directory";
- else
- object.objectHash = currentLocalObjectState.hash;
- [self updateServerStateWithCurrentState:currentLocalObjectState object:object localFilePath:filePath
- accountName:accountName pithosContainer:pithosContainer];
+ accountName:accountName pithosContainer:pithosContainer];
+ } else if (!remoteObject && ![currentLocalObjectState exists]) {
+ // Server state hasn't changed
+ // If the object doesn't exist neither in the server or locally, it should be removed from the stored local objects
+ [containerStoredLocalObjectStates removeObjectForKey:objectName];
+ [self saveLocalState];
+ }
+ } else {
+ // Local state has changed
+ if (!serverStateHasChanged) {
+ // Server state hasn't changed
+ if (currentLocalObjectState.isDirectory)
+ object.contentType = @"application/directory";
+ else
+ object.objectHash = currentLocalObjectState.hash;
+ [self updateServerStateWithCurrentState:currentLocalObjectState object:object localFilePath:filePath
+ accountName:accountName pithosContainer:pithosContainer];
+ } else {
+ // Server state has also changed
+ if (remoteObjectState.isDirectory && currentLocalObjectState.isDirectory) {
+ // Both did the same change (directory)
+ storedLocalObjectState.filePath = filePath;
+ storedLocalObjectState.isDirectory = YES;
+ [self saveLocalState];
+ } else if ([remoteObjectState isEqualToState:currentLocalObjectState]) {
+ // Both did the same change (object edit or delete)
+ if (![remoteObjectState exists]) {
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
+ } else {
+ storedLocalObjectState.filePath = filePath;
+ storedLocalObjectState.hash = remoteObjectState.hash;
+ }
+ [self saveLocalState];
+ } else {
+ // Conflict, we ask the user which change to keep
+ NSString *informativeText;
+ NSString *firstButtonText;
+ NSString *secondButtonText;
+
+ if (![remoteObjectState exists]) {
+ // Remote object has been deleted
+ informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified locally, while it has been deleted from server.",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name ];
+ firstButtonText = @"Delete local file";
+ secondButtonText = @"Upload file to server";
+ } else if (![currentLocalObjectState exists]) {
+ informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified on the server, while it has been deleted locally.",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
+ firstButtonText = @"Download file from server";
+ secondButtonText = @"Delete file on server";
+ } else {
+ informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified both locally and on the server.",
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
+ firstButtonText = @"Keep server version";
+ secondButtonText = @"Keep local version";
+ }
+ __block NSInteger choice;
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setMessageText:@"Conflict"];
+ [alert setInformativeText:informativeText];
+ [alert addButtonWithTitle:firstButtonText];
+ [alert addButtonWithTitle:secondButtonText];
+ [alert addButtonWithTitle:@"Do nothing"];
+ choice = [alert runModal];
+ });
+ if (choice == NSAlertFirstButtonReturn) {
+ object.bytes = remoteObject.bytes;
+ object.version = remoteObject.version;
+ object.contentType = remoteObject.contentType;
+ object.objectHash = remoteObject.objectHash;
+ [self updateLocalStateWithObject:object localFilePath:filePath
+ accountName:accountName pithosContainer:pithosContainer];
+ } if (choice == NSAlertSecondButtonReturn) {
+ if (currentLocalObjectState.isDirectory)
+ object.contentType = @"application/directory";
+ else
+ object.objectHash = currentLocalObjectState.hash;
+ [self updateServerStateWithCurrentState:currentLocalObjectState object:object localFilePath:filePath
+ accountName:accountName pithosContainer:pithosContainer];
+ }
}
}
}
}
}
+ }
+ [self syncOperationFinishedWithSuccess:YES];
+ } else {
+ [self listRequestFailed:containerRequest];
}
- }
- [self syncOperationFinishedWithSuccess:YES];
- } else {
- [self listRequestFailed:containerRequest];
}
- [pool drain];
}
- (void)listRequestFailed:(ASIPithosContainerRequest *)containerRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [containerRequest.userInfo objectForKey:@"operation"];
- if (operation.isCancelled) {
- [objects release];
- objects = nil;
- [pool drain];
- return;
- }
- if (containerRequest.isCancelled) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"]
- withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]];
- });
- [objects release];
- objects = nil;
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
- // If the server listing fails, the sync should start over, so just retrying is enough
- NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
- if (retries > 0) {
- ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[[PithosUtilities copyRequest:containerRequest] autorelease];
- [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
- [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
- } else {
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"]
- withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]];
- });
- [objects release];
- objects = nil;
- // Since the server listing failed in all retries, the operation finished and the sync cycle is completeted unsuccesfully
- [self syncOperationFinishedWithSuccess:NO];
- }
- [pool drain];
-}
-
-- (void)downloadObjectBlockFinished:(ASIPithosObjectRequest *)objectRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::download object block finished: %@", objectRequest.url);
- if (operation.isCancelled) {
- [self requestFailed:objectRequest];
- } else if (objectRequest.responseStatusCode == 206) {
- NSString *accountName = [objectRequest.userInfo objectForKey:@"accountName"];
- ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
- ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- NSError *error;
- PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
-
- NSString *downloadsDirPath = self.tempDownloadsDirPath;
- if (!downloadsDirPath) {
+ @autoreleasepool {
+ NSOperation *operation = [containerRequest.userInfo objectForKey:@"operation"];
+ if (operation.isCancelled) {
+ objects = nil;
+ return;
+ }
+ if (containerRequest.isCancelled) {
dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:activity
- withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
+ [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"]
+ withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]];
});
+ objects = nil;
[self syncOperationFinishedWithSuccess:NO];
- [pool drain];
return;
}
-
- PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:accountName]
- objectForKey:pithosContainer.name]
- objectForKey:object.name];
- if ((storedState.tmpFilePath == nil) || ![fileManager fileExistsAtPath:storedState.tmpFilePath]) {
- NSString *tempFileTemplate = [downloadsDirPath stringByAppendingPathComponent:@"download.XXXXXX"];
- const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
- char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
- strcpy(tempFileNameCString, tempFileTemplateCString);
- int fileDescriptor = mkstemp(tempFileNameCString);
- NSString *tempFilePath = [fileManager stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
- free(tempFileNameCString);
- if (fileDescriptor == -1) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [PithosUtilities fileActionFailedAlertWithTitle:@"Create Temporary File Error"
- message:[NSString stringWithFormat:@"Cannot create temporary file at '%@'", tempFilePath]
- error:nil];
- [activityFacility endActivity:activity
- withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
- close(fileDescriptor);
- storedState.tmpFilePath = tempFilePath;
- [self saveLocalState];
+ // If the server listing fails, the sync should start over, so just retrying is enough
+ NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+ if (retries > 0) {
+ ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest];
+ [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ } else {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"]
+ withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]];
+ });
+ objects = nil;
+ // Since the server listing failed in all retries, the operation finished and the sync cycle is completeted unsuccesfully
+ [self syncOperationFinishedWithSuccess:NO];
}
+ }
+}
- NSUInteger missingBlockIndex = [[objectRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
- NSFileHandle *tempFileHandle = [NSFileHandle fileHandleForWritingAtPath:storedState.tmpFilePath];
- [tempFileHandle seekToFileOffset:missingBlockIndex*pithosContainer.blockSize];
- [tempFileHandle writeData:[objectRequest responseData]];
- [tempFileHandle closeFile];
-
- NSIndexSet *missingBlocks = [objectRequest.userInfo objectForKey:@"missingBlocks"];
- missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex];
- if (missingBlockIndex == NSNotFound) {
- NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
- NSString *dirPath = [filePath stringByDeletingLastPathComponent];
- if ([fileManager fileExistsAtPath:filePath] && ![self moveToTempTrashFile:filePath
- accountName:accountName
- pithosContainer:pithosContainer]) {
+- (void)downloadObjectBlockFinished:(ASIPithosObjectRequest *)objectRequest {
+ @autoreleasepool {
+ NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::download object block finished: %@", objectRequest.url);
+ if (operation.isCancelled) {
+ [self requestFailed:objectRequest];
+ } else if (objectRequest.responseStatusCode == 206) {
+ NSString *accountName = [objectRequest.userInfo objectForKey:@"accountName"];
+ ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
+ ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSError *error;
+ PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
+
+ NSString *downloadsDirPath = self.tempDownloadsDirPath;
+ if (!downloadsDirPath) {
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility endActivity:activity
withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
});
[self syncOperationFinishedWithSuccess:NO];
- [pool drain];
return;
- } else if (![fileManager fileExistsAtPath:dirPath]) {
- // File doesn't exist but also the containing directory doesn't exist
- // In most cases this should have been resolved as an update of the corresponding local object,
- // but it never hurts to check
- error = nil;
- [fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];
- if (error != nil) {
+ }
+
+ PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name]
+ objectForKey:object.name];
+ if ((storedState.tmpFilePath == nil) || ![fileManager fileExistsAtPath:storedState.tmpFilePath]) {
+ NSString *tempFileTemplate = [downloadsDirPath stringByAppendingPathComponent:@"download.XXXXXX"];
+ const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
+ char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
+ strcpy(tempFileNameCString, tempFileTemplateCString);
+ int fileDescriptor = mkstemp(tempFileNameCString);
+ NSString *tempFilePath = [fileManager stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
+ free(tempFileNameCString);
+ if (fileDescriptor == -1) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Create Temporary File Error"
+ message:[NSString stringWithFormat:@"Cannot create temporary file at '%@'", tempFilePath]
+ error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
- [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
- message:[NSString stringWithFormat:@"Cannot create directory at '%@'", dirPath]
- error:error];
- [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
+ [activityFacility endActivity:activity
withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
});
[self syncOperationFinishedWithSuccess:NO];
- [pool drain];
return;
}
+ close(fileDescriptor);
+ storedState.tmpFilePath = tempFilePath;
+ [self saveLocalState];
}
- // Move file from tmp download
- error = nil;
- [fileManager moveItemAtPath:storedState.tmpFilePath toPath:filePath error:&error];
- if (error != nil) {
- dispatch_async(dispatch_get_main_queue(), ^{
+
+ NSUInteger missingBlockIndex = [[objectRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
+ NSFileHandle *tempFileHandle = [NSFileHandle fileHandleForWritingAtPath:storedState.tmpFilePath];
+ [tempFileHandle seekToFileOffset:missingBlockIndex*pithosContainer.blockSize];
+ [tempFileHandle writeData:[objectRequest responseData]];
+ [tempFileHandle closeFile];
+
+ NSIndexSet *missingBlocks = [objectRequest.userInfo objectForKey:@"missingBlocks"];
+ missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex];
+ if (missingBlockIndex == NSNotFound) {
+ NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
+ NSString *dirPath = [filePath stringByDeletingLastPathComponent];
+ if ([fileManager fileExistsAtPath:filePath] && ![self moveToTempTrashFile:filePath
+ accountName:accountName
+ pithosContainer:pithosContainer]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:activity
+ withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ } else if (![fileManager fileExistsAtPath:dirPath]) {
+ // File doesn't exist but also the containing directory doesn't exist
+ // In most cases this should have been resolved as an update of the corresponding local object,
+ // but it never hurts to check
+ error = nil;
+ [fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];
+ if (error != nil) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error"
+ message:[NSString stringWithFormat:@"Cannot create directory at '%@'", dirPath]
+ error:error];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
+ withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+ }
+ // Move file from tmp download
+ error = nil;
+ [fileManager moveItemAtPath:storedState.tmpFilePath toPath:filePath error:&error];
+ if (error != nil) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error"
message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", storedState.tmpFilePath, filePath]
error:error];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:activity
+ withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility endActivity:activity
- withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
+ withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]
+ totalBytes:activity.totalBytes
+ currentBytes:activity.totalBytes];
});
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
+
+ storedState.filePath = filePath;
+ storedState.hash = object.objectHash;
+ storedState.tmpFilePath = nil;
+ [self saveLocalState];
+ [self syncOperationFinishedWithSuccess:YES];
return;
+ } else {
+ if (newSyncRequested || syncLate || operation.isCancelled) {
+ [self requestFailed:objectRequest];
+ } else {
+ __block ASIPithosObjectRequest *newObjectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ object:object
+ blockIndex:missingBlockIndex
+ blockSize:pithosContainer.blockSize];
+ if (![accountName isEqualToString:@""])
+ [newObjectRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
+ newObjectRequest.delegate = self;
+ newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ newObjectRequest.userInfo = objectRequest.userInfo;
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
+ [newObjectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
+ [activityFacility updateActivity:activity
+ withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
+ [newObjectRequest.userInfo objectForKey:@"messagePrefix"],
+ (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ totalBytes:activity.totalBytes
+ currentBytes:(activity.currentBytes + size)];
+ }];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ }
}
+ } else if (objectRequest.responseStatusCode == 412) {
+ // The object has changed on the server
dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:activity
- withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]
- totalBytes:activity.totalBytes
- currentBytes:activity.totalBytes];
+ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
+ withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]];
});
-
- storedState.filePath = filePath;
- storedState.hash = object.objectHash;
- storedState.tmpFilePath = nil;
- [self saveLocalState];
- [self syncOperationFinishedWithSuccess:YES];
- [pool drain];
- return;
+ [self syncOperationFinishedWithSuccess:NO];
} else {
+ [self requestFailed:objectRequest];
+ }
+ }
+}
+
+- (void)downloadObjectHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
+ @autoreleasepool {
+ NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::download object hashmap finished: %@", objectRequest.url);
+ if (operation.isCancelled) {
+ [self requestFailed:objectRequest];
+ } else if (objectRequest.responseStatusCode == 200) {
if (newSyncRequested || syncLate || operation.isCancelled) {
[self requestFailed:objectRequest];
} else {
- __block ASIPithosObjectRequest *newObjectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
+ NSString *accountName = [objectRequest.userInfo objectForKey:@"accountName"];
+ ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
+ ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
+ PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name]
+ objectForKey:object.name];
+ if ([PithosUtilities bytesOfFile:storedState.tmpFilePath] > object.bytes)
+ [[NSFileHandle fileHandleForWritingAtPath:storedState.tmpFilePath] truncateFileAtOffset:object.bytes];
+ PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
+ NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForFile:storedState.tmpFilePath
+ blockSize:pithosContainer.blockSize
+ blockHash:pithosContainer.blockHash
+ withHashes:[objectRequest hashes]];
+ NSUInteger missingBlockIndex = [missingBlocks firstIndex];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity
+ withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
+ [objectRequest.userInfo objectForKey:@"messagePrefix"],
+ (100*(activity.totalBytes - [missingBlocks count]*pithosContainer.blockSize + 0.0)/(activity.totalBytes + 0.0))]
+ totalBytes:activity.totalBytes
+ currentBytes:(activity.totalBytes - [missingBlocks count]*pithosContainer.blockSize)];
+ });
+
+ __block ASIPithosObjectRequest *newObjectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
containerName:pithosContainer.name
object:object
blockIndex:missingBlockIndex
newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
newObjectRequest.userInfo = objectRequest.userInfo;
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
[(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
[(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(downloadObjectBlockFinished:)) forKey:@"didFinishSelector"];
[newObjectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
}];
[networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]];
}
+ } else {
+ [self requestFailed:objectRequest];
}
- } else if (objectRequest.responseStatusCode == 412) {
- // The object has changed on the server
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
- withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:NO];
- } else {
- [self requestFailed:objectRequest];
}
- [pool drain];
}
-- (void)downloadObjectHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::download object hashmap finished: %@", objectRequest.url);
- if (operation.isCancelled) {
- [self requestFailed:objectRequest];
- } else if (objectRequest.responseStatusCode == 200) {
- if (newSyncRequested || syncLate || operation.isCancelled) {
+- (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest {
+ @autoreleasepool {
+ NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::upload directory object finished: %@", objectRequest.url);
+ if (operation.isCancelled) {
[self requestFailed:objectRequest];
- } else {
- NSString *accountName = [objectRequest.userInfo objectForKey:@"accountName"];
- ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
- ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
- PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:accountName]
- objectForKey:pithosContainer.name]
- objectForKey:object.name];
- if ([PithosUtilities bytesOfFile:storedState.tmpFilePath] > object.bytes)
- [[NSFileHandle fileHandleForWritingAtPath:storedState.tmpFilePath] truncateFileAtOffset:object.bytes];
- PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
- NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForFile:storedState.tmpFilePath
- blockSize:pithosContainer.blockSize
- blockHash:pithosContainer.blockHash
- withHashes:[objectRequest hashes]];
- NSUInteger missingBlockIndex = [missingBlocks firstIndex];
+ } else if (objectRequest.responseStatusCode == 201) {
+ PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:[objectRequest.userInfo objectForKey:@"accountName"]]
+ objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ objectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
+ storedState.isDirectory = YES;
+ [self saveLocalState];
dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
- [objectRequest.userInfo objectForKey:@"messagePrefix"],
- (100*(activity.totalBytes - [missingBlocks count]*pithosContainer.blockSize + 0.0)/(activity.totalBytes + 0.0))]
- totalBytes:activity.totalBytes
- currentBytes:(activity.totalBytes - [missingBlocks count]*pithosContainer.blockSize)];
+ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
+ withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
});
-
- __block ASIPithosObjectRequest *newObjectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
- containerName:pithosContainer.name
- object:object
- blockIndex:missingBlockIndex
- blockSize:pithosContainer.blockSize];
- if (![accountName isEqualToString:@""])
- [newObjectRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
- newObjectRequest.delegate = self;
- newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- newObjectRequest.userInfo = objectRequest.userInfo;
- [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
- [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
- [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
- [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(downloadObjectBlockFinished:)) forKey:@"didFinishSelector"];
- [newObjectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
- [activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
- [newObjectRequest.userInfo objectForKey:@"messagePrefix"],
- (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
- totalBytes:activity.totalBytes
- currentBytes:(activity.currentBytes + size)];
- }];
- [networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ [self syncOperationFinishedWithSuccess:YES];
+ } else {
+ [self requestFailed:objectRequest];
}
- } else {
- [self requestFailed:objectRequest];
- }
- [pool drain];
-}
-
-- (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::upload directory object finished: %@", objectRequest.url);
- if (operation.isCancelled) {
- [self requestFailed:objectRequest];
- } else if (objectRequest.responseStatusCode == 201) {
- PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:[objectRequest.userInfo objectForKey:@"accountName"]]
- objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
- objectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
- storedState.isDirectory = YES;
- [self saveLocalState];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
- withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:YES];
- } else {
- [self requestFailed:objectRequest];
}
- [pool drain];
}
- (void)moveObjectToTrashFinished:(ASIPithosObjectRequest *)objectRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::move object to trash finished: %@", objectRequest.url);
- if (operation.isCancelled) {
- [self requestFailed:objectRequest];
- } else if (objectRequest.responseStatusCode == 201) {
- [[[storedLocalObjectStates objectForKey:[objectRequest.userInfo objectForKey:@"accountName"]]
- objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
- removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
- [self saveLocalState];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
- withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:YES];
- } else {
- [self requestFailed:objectRequest];
+ @autoreleasepool {
+ NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::move object to trash finished: %@", objectRequest.url);
+ if (operation.isCancelled) {
+ [self requestFailed:objectRequest];
+ } else if (objectRequest.responseStatusCode == 201) {
+ [[[storedLocalObjectStates objectForKey:[objectRequest.userInfo objectForKey:@"accountName"]]
+ objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
+ [self saveLocalState];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
+ withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:YES];
+ } else {
+ [self requestFailed:objectRequest];
+ }
}
- [pool drain];
}
- (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::delete object finished: %@", objectRequest.url);
- if (operation.isCancelled) {
- [self requestFailed:objectRequest];
- } else if (objectRequest.responseStatusCode == 204) {
- [[[storedLocalObjectStates objectForKey:[objectRequest.userInfo objectForKey:@"accountName"]]
- objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
- removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
- [self saveLocalState];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
- withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:YES];
- } else {
- [self requestFailed:objectRequest];
- }
- [pool drain];
-}
-
-- (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::upload using hashmap finished: %@", objectRequest.url);
- NSString *accountName = [objectRequest.userInfo objectForKey:@"accountName"];
- ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
- ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
- PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:accountName]
- objectForKey:pithosContainer.name]
- objectForKey:object.name];
- PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
- NSUInteger totalBytes = activity.totalBytes;
- NSUInteger currentBytes = activity.currentBytes;
- if (operation.isCancelled) {
- [self requestFailed:objectRequest];
- } else if (objectRequest.responseStatusCode == 201) {
- NSLog(@"Sync::object created: %@", objectRequest.url);
- storedState.filePath = [objectRequest.userInfo objectForKey:@"filePath"];
- storedState.hash = object.objectHash;
- [self saveLocalState];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:activity
- withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]
- totalBytes:totalBytes
- currentBytes:totalBytes];
- });
- [self syncOperationFinishedWithSuccess:YES];
- } else if (objectRequest.responseStatusCode == 409) {
- if (newSyncRequested || syncLate || operation.isCancelled) {
+ @autoreleasepool {
+ NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::delete object finished: %@", objectRequest.url);
+ if (operation.isCancelled) {
[self requestFailed:objectRequest];
- } else {
- NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue];
- if (iteration == 0) {
- NSLog(@"Sync::upload iteration limit reached: %@", objectRequest.url);
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:activity withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
- NSLog(@"Sync::object is missing hashes: %@", objectRequest.url);
- NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
- withMissingHashes:[objectRequest hashes]];
- if (totalBytes >= [missingBlocks count]*pithosContainer.blockSize)
- currentBytes = totalBytes - [missingBlocks count]*pithosContainer.blockSize;
+ } else if (objectRequest.responseStatusCode == 204) {
+ [[[storedLocalObjectStates objectForKey:[objectRequest.userInfo objectForKey:@"accountName"]]
+ objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
+ [self saveLocalState];
dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
- [objectRequest.userInfo objectForKey:@"messagePrefix"],
- (100*(currentBytes + 0.0)/(totalBytes + 0.0))]
- totalBytes:totalBytes
- currentBytes:currentBytes];
+ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
+ withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
});
- NSUInteger missingBlockIndex = [missingBlocks firstIndex];
- __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithos
- containerName:pithosContainer.name
- blockSize:pithosContainer.blockSize
- forFile:[objectRequest.userInfo objectForKey:@"filePath"]
- missingBlockIndex:missingBlockIndex
- sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
- newContainerRequest.delegate = self;
- newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- newContainerRequest.userInfo = objectRequest.userInfo;
- [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:(--iteration)] forKey:@"iteration"];
- [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
- [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
- [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
- [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadMissingBlockFinished:)) forKey:@"didFinishSelector"];
- [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
- [activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
- [newContainerRequest.userInfo objectForKey:@"messagePrefix"],
- (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
- totalBytes:activity.totalBytes
- currentBytes:(activity.currentBytes + size)];
- }];
- [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ [self syncOperationFinishedWithSuccess:YES];
+ } else {
+ [self requestFailed:objectRequest];
}
- } else {
- [self requestFailed:objectRequest];
}
- [pool drain];
}
-- (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [containerRequest.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::upload of missing block finished: %@", containerRequest.url);
- if (operation.isCancelled) {
- [self requestFailed:containerRequest];
- } else if (containerRequest.responseStatusCode == 202) {
- NSString *accountName = [containerRequest.userInfo objectForKey:@"accountName"];
- ASIPithosContainer *pithosContainer = [containerRequest.userInfo objectForKey:@"pithosContainer"];
- ASIPithosObject *object = [containerRequest.userInfo objectForKey:@"pithosObject"];
- PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"];
- NSIndexSet *missingBlocks = [containerRequest.userInfo objectForKey:@"missingBlocks"];
- NSUInteger missingBlockIndex = [[containerRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
- missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex];
+- (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
+ @autoreleasepool {
+ NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::upload using hashmap finished: %@", objectRequest.url);
+ NSString *accountName = [objectRequest.userInfo objectForKey:@"accountName"];
+ ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
+ ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
+ PithosLocalObjectState *storedState = [[[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name]
+ objectForKey:object.name];
+ PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
+ NSUInteger totalBytes = activity.totalBytes;
+ NSUInteger currentBytes = activity.currentBytes;
if (operation.isCancelled) {
- [self requestFailed:containerRequest];
- } else if (missingBlockIndex == NSNotFound) {
- NSArray *hashes = [containerRequest.userInfo objectForKey:@"hashes"];
- ASIPithosObjectRequest *newObjectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos
- containerName:pithosContainer.name
- objectName:object.name
- contentType:object.contentType
- blockSize:pithosContainer.blockSize
- blockHash:pithosContainer.blockHash
- forFile:[containerRequest.userInfo objectForKey:@"filePath"]
- checkIfExists:NO
- hashes:&hashes
- sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
- newObjectRequest.delegate = self;
- newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- newObjectRequest.userInfo = containerRequest.userInfo;
- [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
- [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"];
- [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"];
- [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)) forKey:@"didFinishSelector"];
- [networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]];
- } else {
+ [self requestFailed:objectRequest];
+ } else if (objectRequest.responseStatusCode == 201) {
+ DLog(@"Sync::object created: %@", objectRequest.url);
+ storedState.filePath = [objectRequest.userInfo objectForKey:@"filePath"];
+ storedState.hash = object.objectHash;
+ [self saveLocalState];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:activity
+ withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]
+ totalBytes:totalBytes
+ currentBytes:totalBytes];
+ });
+ [self syncOperationFinishedWithSuccess:YES];
+ } else if (objectRequest.responseStatusCode == 409) {
if (newSyncRequested || syncLate || operation.isCancelled) {
- [self requestFailed:containerRequest];
+ [self requestFailed:objectRequest];
} else {
- __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithos
- containerName:pithosContainer.name
- blockSize:pithosContainer.blockSize
- forFile:[containerRequest.userInfo objectForKey:@"filePath"]
+ NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue];
+ if (iteration == 0) {
+ DLog(@"Sync::upload iteration limit reached: %@", objectRequest.url);
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:activity withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+ DLog(@"Sync::object is missing hashes: %@", objectRequest.url);
+ NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
+ withMissingHashes:[objectRequest hashes]];
+ if (totalBytes >= [missingBlocks count]*pithosContainer.blockSize)
+ currentBytes = totalBytes - [missingBlocks count]*pithosContainer.blockSize;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity
+ withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
+ [objectRequest.userInfo objectForKey:@"messagePrefix"],
+ (100*(currentBytes + 0.0)/(totalBytes + 0.0))]
+ totalBytes:totalBytes
+ currentBytes:currentBytes];
+ });
+ NSUInteger missingBlockIndex = [missingBlocks firstIndex];
+ __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ blockSize:pithosContainer.blockSize
+ forFile:[objectRequest.userInfo objectForKey:@"filePath"]
missingBlockIndex:missingBlockIndex
sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
newContainerRequest.delegate = self;
newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- newContainerRequest.userInfo = containerRequest.userInfo;
+ newContainerRequest.userInfo = objectRequest.userInfo;
+ [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:(--iteration)] forKey:@"iteration"];
[(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
+ [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
[(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
+ [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadMissingBlockFinished:)) forKey:@"didFinishSelector"];
[newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
}];
[networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
}
+ } else {
+ [self requestFailed:objectRequest];
}
- } else {
- [self requestFailed:containerRequest];
}
- [pool drain];
}
-- (void)requestFailed:(ASIPithosRequest *)request {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSOperation *operation = [request.userInfo objectForKey:@"operation"];
- NSLog(@"Sync::request failed: %@", request.url);
- if (operation.isCancelled) {
- [pool drain];
- return;
- }
- if (request.isCancelled || newSyncRequested || syncLate) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
- withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
+- (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest {
+ @autoreleasepool {
+ NSOperation *operation = [containerRequest.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::upload of missing block finished: %@", containerRequest.url);
+ if (operation.isCancelled) {
+ [self requestFailed:containerRequest];
+ } else if (containerRequest.responseStatusCode == 202) {
+ NSString *accountName = [containerRequest.userInfo objectForKey:@"accountName"];
+ ASIPithosContainer *pithosContainer = [containerRequest.userInfo objectForKey:@"pithosContainer"];
+ ASIPithosObject *object = [containerRequest.userInfo objectForKey:@"pithosObject"];
+ PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"];
+ NSIndexSet *missingBlocks = [containerRequest.userInfo objectForKey:@"missingBlocks"];
+ NSUInteger missingBlockIndex = [[containerRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
+ missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex];
+ if (operation.isCancelled) {
+ [self requestFailed:containerRequest];
+ } else if (missingBlockIndex == NSNotFound) {
+ NSArray *hashes = [containerRequest.userInfo objectForKey:@"hashes"];
+ ASIPithosObjectRequest *newObjectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name
+ contentType:object.contentType
+ blockSize:pithosContainer.blockSize
+ blockHash:pithosContainer.blockHash
+ forFile:[containerRequest.userInfo objectForKey:@"filePath"]
+ checkIfExists:NO
+ hashes:&hashes
+ sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
+ newObjectRequest.delegate = self;
+ newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ newObjectRequest.userInfo = containerRequest.userInfo;
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"];
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"];
+ [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)) forKey:@"didFinishSelector"];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ } else {
+ if (newSyncRequested || syncLate || operation.isCancelled) {
+ [self requestFailed:containerRequest];
+ } else {
+ __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ blockSize:pithosContainer.blockSize
+ forFile:[containerRequest.userInfo objectForKey:@"filePath"]
+ missingBlockIndex:missingBlockIndex
+ sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
+ newContainerRequest.delegate = self;
+ newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ newContainerRequest.userInfo = containerRequest.userInfo;
+ [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
+ [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
+ [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
+ [activityFacility updateActivity:activity
+ withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
+ [newContainerRequest.userInfo objectForKey:@"messagePrefix"],
+ (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ totalBytes:activity.totalBytes
+ currentBytes:(activity.currentBytes + size)];
+ }];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ }
+ }
+ } else {
+ [self requestFailed:containerRequest];
+ }
}
- NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
- if (retries > 0) {
- ASIPithosRequest *newRequest = (ASIPithosRequest *)[[PithosUtilities copyRequest:request] autorelease];
- [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
- [networkQueue addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]];
- } else {
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
- withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]];
- });
- [self syncOperationFinishedWithSuccess:NO];
+}
+
+- (void)requestFailed:(ASIPithosRequest *)request {
+ @autoreleasepool {
+ NSOperation *operation = [request.userInfo objectForKey:@"operation"];
+ DLog(@"Sync::request failed: %@", request.url);
+ if (operation.isCancelled)
+ return;
+ if (request.isCancelled || newSyncRequested || syncLate) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
+ withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+ NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+ if (retries > 0) {
+ ASIPithosRequest *newRequest = (ASIPithosRequest *)[PithosUtilities copyRequest:request];
+ [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ } else {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[request.userInfo objectForKey:@"activity"]
+ withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:NO];
+ }
}
- [pool drain];
}
@end