- (void)resetLocalStateWithAll:(BOOL)all;
- (void)saveLocalState;
-- (BOOL)moveToTempTrashFile:(NSString *)filePath pithosContainer:(ASIPithosContainer *)pithosContainer;
+- (BOOL)createSyncDirectory:(NSString *)dirPath;
+- (NSString *)dirPathForAccount:(NSString *)accountName container:(NSString *)containerName;
+- (NSString *)relativeDirPathForAccount:(NSString *)accountName container:(NSString *)containerName;
+
+- (BOOL)moveToTempTrashFile:(NSString *)filePath
+ accountName:(NSString *)accountName
+ pithosContainer:(ASIPithosContainer *)pithosContainer;
- (void)emptyTempTrash;
- (BOOL)findLocalCopyForObjectWithHash:(NSString *)hash forFile:(NSString *)filePath;
- (void)updateLocalStateWithObject:(ASIPithosObject *)object
localFilePath:(NSString *)filePath
+ accountName:(NSString *)accountName
pithosContainer:(ASIPithosContainer *)pithosContainer;
- (void)updateServerStateWithCurrentState:(PithosLocalObjectState *)currentState
object:(ASIPithosObject *)object
localFilePath:(NSString *)filePath
+ accountName:(NSString *)accountName
pithosContainer:(ASIPithosContainer *)pithosContainer;
- (void)listRequestFailed:(ASIPithosContainerRequest *)containerRequest;
- (void)requestFailed:(ASIPithosRequest *)request;
@implementation PithosSyncDaemon
@synthesize directoryPath, accountsDictionary, pithos;
-@synthesize containersDictionary, pithosContainers;
+@synthesize accountsNames, accountsPithosContainers;
@synthesize lastCompletedSync, remoteObjects, previousRemoteObjects, storedLocalObjectStates, currentLocalObjectStates;
@synthesize pithosStateFilePath, tempDownloadsDirPath, tempTrashDirPath;
if ((self = [super init])) {
directoryPath = [aDirectoryPath copy];
pithosAccount = [aPithosAccount retain];
- accountsDictionary = [anAccountsDictionary copy];
- self.pithos = pithosAccount.pithos;
-
- self.containersDictionary = [accountsDictionary objectForKey:@""];
- if (!containersDictionary)
- self.containersDictionary = [NSDictionary dictionary];
- containersCount = [containersDictionary count];
- self.pithosContainers = [NSMutableArray arrayWithCapacity:containersCount];
- for (NSString *containerName in containersDictionary) {
- ASIPithosContainer *pithosContainer = [ASIPithosContainer container];
- pithosContainer.name = containerName;
- [pithosContainers addObject:pithosContainer];
- }
+ self.accountsDictionary = anAccountsDictionary;
+ self.pithos = pithosAccount.pithos;
activityFacility = [PithosActivityFacility defaultPithosActivityFacility];
self.storedLocalObjectStates = [NSMutableDictionary dictionary];
if (!storedLocalObjectStates)
self.storedLocalObjectStates = [NSMutableDictionary dictionary];
- for (ASIPithosContainer *pithosContainer in pithosContainers) {
- if (![storedLocalObjectStates objectForKey:pithosContainer.name]) {
- [storedLocalObjectStates setObject:[NSMutableDictionary dictionary] forKey:pithosContainer.name];
+ 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;
- NSFileManager *fileManager = [NSFileManager defaultManager];
- NSError *error;
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) {
- error = nil;
- for (NSString *subPath in [fileManager contentsOfDirectoryAtPath:self.tempDownloadsDirPath error:&error]) {
- if (error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
- message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", self.tempDownloadsDirPath]
- error:error];
- break;
- }
- NSString *subFilePath = [self.tempDownloadsDirPath stringByAppendingPathComponent:subPath];
- if (![fileManager removeItemAtPath:subFilePath error:&error] || error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
- message:[NSString stringWithFormat:@"Cannot remove file at '%@'", subFilePath]
- error:error];
- }
- error = nil;
- }
- }
+ if (self.tempDownloadsDirPath)
+ [PithosUtilities removeContentsAtPath:self.tempDownloadsDirPath];
} else {
// Remove containers that don't interest us anymore and save
if (!storedLocalObjectStates)
[self loadLocalState];
- for (NSString *containerName in storedLocalObjectStates) {
- if (![containersDictionary objectForKey:containerName]) {
- [storedLocalObjectStates removeObjectForKey:containerName];
+ for (NSString *accountName in storedLocalObjectStates) {
+ NSMutableDictionary *accountStoredLocalObjectStates = [storedLocalObjectStates objectForKey:accountName];
+ NSDictionary *containersDictionary = [accountsDictionary objectForKey:accountName];
+ if (!containersDictionary) {
if (self.tempDownloadsDirPath) {
- NSString *containerTempDownloadsDirPath = [self.tempDownloadsDirPath stringByAppendingPathComponent:containerName];
- BOOL isDirectory;
- BOOL fileExists = [fileManager fileExistsAtPath:containerTempDownloadsDirPath isDirectory:&isDirectory];
- if (fileExists && isDirectory) {
- error = nil;
- for (NSString *subPath in [fileManager contentsOfDirectoryAtPath:containerTempDownloadsDirPath error:&error]) {
- if (error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
- message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'",
- containerTempDownloadsDirPath]
- error:error];
- break;
- }
- NSString *subFilePath = [containerTempDownloadsDirPath stringByAppendingPathComponent:subPath];
- if (![fileManager removeItemAtPath:subFilePath error:&error] || error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
- message:[NSString stringWithFormat:@"Cannot remove file at '%@'",
- subFilePath]
- error:error];
- }
- error = nil;
- }
- } else if (fileExists && !isDirectory) {
- error = nil;
- if (![fileManager removeItemAtPath:containerTempDownloadsDirPath error:&error] || error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
- message:[NSString stringWithFormat:@"Cannot remove file at '%@'",
- containerTempDownloadsDirPath]
- error:error];
+ if ([accountName isEqualToString:@""]) {
+ for (NSString *containerName in accountStoredLocalObjectStates) {
+ [PithosUtilities removeContentsAtPath:[self.tempDownloadsDirPath stringByAppendingPathComponent:containerName]];
}
+ } 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];
}
}
}
[remoteObjects release];
[objects release];
[lastCompletedSync release];
- [pithosContainers release];
- [containersDictionary release];
+ [accountsPithosContainers release];
+ [accountsNames release];
[pithos release];
[accountsDictionary release];
[pithosAccount release];
- (void)setAccountsDictionary:(NSDictionary *)anAccountsDictionary {
if (anAccountsDictionary && ![anAccountsDictionary isEqualToDictionary:accountsDictionary]) {
- [self resetDaemon];
+ BOOL reset = (accountsDictionary != nil);
+ if (reset)
+ [self resetDaemon];
+
[accountsDictionary release];
accountsDictionary = [anAccountsDictionary copy];
- self.containersDictionary = [accountsDictionary objectForKey:@""];
- if (!containersDictionary)
- self.containersDictionary = [NSDictionary dictionary];
- containersCount = [containersDictionary count];
- self.pithosContainers = [NSMutableArray arrayWithCapacity:containersCount];
- for (NSString *containerName in containersDictionary) {
- ASIPithosContainer *pithosContainer = [ASIPithosContainer container];
- pithosContainer.name = containerName;
- [pithosContainers addObject:pithosContainer];
+ accountsCount = [accountsDictionary count];
+ self.accountsNames = [NSMutableArray arrayWithCapacity:accountsCount];
+ self.accountsPithosContainers = [NSMutableDictionary dictionaryWithCapacity:accountsCount];
+ NSDictionary *containersDictionary = [accountsDictionary objectForKey:@""];
+ if (containersDictionary && [containersDictionary count]) {
+ NSMutableArray *pithosContainers = [NSMutableArray arrayWithCapacity:[containersDictionary count]];
+ for (NSString *containerName in containersDictionary) {
+ ASIPithosContainer *pithosContainer = [ASIPithosContainer container];
+ pithosContainer.name = containerName;
+ [pithosContainers addObject:pithosContainer];
+ }
+ [accountsNames addObject:@""];
+ [accountsPithosContainers setObject:pithosContainers forKey:@""];
+ }
+ for (NSString *accountName in accountsDictionary) {
+ NSDictionary *containersDictionary = [accountsDictionary objectForKey:accountName];
+ if (![accountsNames containsObject:accountName] && [containersDictionary count]) {
+ NSMutableArray *pithosContainers = [NSMutableArray arrayWithCapacity:[containersDictionary count]];
+ for (NSString *containerName in containersDictionary) {
+ ASIPithosContainer *pithosContainer = [ASIPithosContainer container];
+ pithosContainer.name = containerName;
+ [pithosContainers addObject:pithosContainer];
+ }
+ [accountsNames addObject:accountName];
+ [accountsPithosContainers setObject:pithosContainers forKey:accountName];
+ }
}
- [self resetLocalStateWithAll:NO];
+
+ if (reset)
+ [self resetLocalStateWithAll:NO];
}
}
}
#pragma mark -
+#pragma mark Helper Methods
+
+- (BOOL)createSyncDirectory:(NSString *)dirPath {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory;
+ NSError *error = nil;
+ if (![fileManager fileExistsAtPath:dirPath isDirectory:&isDirectory]) {
+ if (![fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
+ message:[NSString stringWithFormat:@"Cannot create local sync directory at '%@'",
+ dirPath]
+ error:error];
+ return NO;
+ }
+ } else if (!isDirectory) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
+ message:[NSString stringWithFormat:@"File already exists at the local sync directory path at '%@'",
+ dirPath]
+ error:nil];
+ return NO;
+ }
+ return YES;
+}
+
+- (NSString *)dirPathForAccount:(NSString *)accountName container:(NSString *)containerName {
+ if ([accountName isEqualToString:@""])
+ return [directoryPath stringByAppendingPathComponent:containerName];
+ else
+ return [[[directoryPath stringByAppendingPathComponent:@"shared to me"]
+ stringByAppendingPathComponent:accountName]
+ stringByAppendingPathComponent:containerName];
+}
+
+- (NSString *)relativeDirPathForAccount:(NSString *)accountName container:(NSString *)containerName {
+ if ([accountName isEqualToString:@""])
+ return containerName;
+ else
+ return [[[NSString stringWithString:@"shared to me"]
+ stringByAppendingPathComponent:accountName]
+ stringByAppendingPathComponent:containerName];
+}
+
+#pragma mark -
#pragma mark Sync
- (void)syncOperationStarted {
// If at least one operation is running return
newSyncRequested = YES;
return;
- } else if (daemonActive && containersCount) {
+ } else if (daemonActive && accountsCount) {
// The first operation is the server listing
[self syncOperationStarted];
newSyncRequested = NO;
}
}
- NSFileManager *fileManager = [NSFileManager defaultManager];
- BOOL isDirectory;
- NSError *error = nil;
- if (![fileManager fileExistsAtPath:directoryPath isDirectory:&isDirectory]) {
- if (![fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error] ||
- error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
- message:[NSString stringWithFormat:@"Cannot create local sync directory at '%@'", directoryPath]
- error:error];
- [self syncOperationFinishedWithSuccess:NO];
- return;
- }
- } else if (!isDirectory) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
- message:[NSString stringWithFormat:@"File already exists at the local sync directory path at '%@'", directoryPath]
- error:nil];
+ if (![self createSyncDirectory:directoryPath]) {
[self syncOperationFinishedWithSuccess:NO];
return;
}
- for (ASIPithosContainer *pithosContainer in pithosContainers) {
- NSString *containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
- error = nil;
- if (![fileManager fileExistsAtPath:containerDirectoryPath isDirectory:&isDirectory]) {
- if (![fileManager createDirectoryAtPath:containerDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error] ||
- error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
- message:[NSString stringWithFormat:@"Cannot create local sync directory at '%@'",
- containerDirectoryPath]
- error:error];
+ for (NSString *accountName in accountsNames) {
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ if (![self createSyncDirectory:[self dirPathForAccount:accountName container:pithosContainer.name]]) {
[self syncOperationFinishedWithSuccess:NO];
return;
}
- } else if (!isDirectory) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
- message:[NSString stringWithFormat:@"File already exists at the local sync directory path at '%@'",
- containerDirectoryPath]
- error:nil];
- [self syncOperationFinishedWithSuccess:NO];
- return;
}
}
+
+ self.remoteObjects = [NSMutableDictionary dictionaryWithCapacity:accountsCount];
+ for (NSString *accountName in accountsNames) {
+ [remoteObjects setObject:[NSMutableDictionary dictionary] forKey:accountName];
+ }
+ accountsIndex = 0;
containersIndex = 0;
- self.remoteObjects = [NSMutableDictionary dictionaryWithCapacity:containersCount];
+ NSString *accountName = [accountsNames objectAtIndex:accountsIndex];
+ ASIPithosContainer *pithosContainer = [[accountsPithosContainers objectForKey:accountName] objectAtIndex:containersIndex];
ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
- containerName:[[pithosContainers objectAtIndex:containersIndex] name]
+ containerName:pithosContainer.name
limit:0
marker:nil
prefix:nil
meta:nil
shared:NO
until:nil
- ifModifiedSince:[[pithosContainers objectAtIndex:containersIndex] lastModified]];
+ ifModifiedSince:pithosContainer.lastModified];
+ if (![accountName isEqualToString:@""])
+ [containerRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
containerRequest.delegate = self;
containerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
containerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
[pool drain];
}
-- (BOOL)moveToTempTrashFile:(NSString *)filePath pithosContainer:(ASIPithosContainer *)pithosContainer {
+- (BOOL)moveToTempTrashFile:(NSString *)filePath
+ accountName:(NSString *)accountName
+ pithosContainer:(ASIPithosContainer *)pithosContainer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (!self.tempTrashDirPath) {
[pool drain];
BOOL isDirectory;
BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
NSError *error = nil;
- NSString *containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
+ NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
NSString *newFilePath = [filePath stringByReplacingOccurrencesOfString:containerDirectoryPath withString:self.tempTrashDirPath];
NSString *newDirPath = [newFilePath stringByDeletingLastPathComponent];
if (fileExists && isDirectory) {
- (void)updateLocalStateWithObject:(ASIPithosObject *)object
localFilePath:(NSString *)filePath
+ accountName:(NSString *)accountName
pithosContainer:(ASIPithosContainer *)pithosContainer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory;
BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
NSString *fileDirectoryPath = [filePath stringByDeletingLastPathComponent];
- NSMutableDictionary *containerStoredLocalObjectStates = [storedLocalObjectStates objectForKey:pithosContainer.name];
+ NSMutableDictionary *containerStoredLocalObjectStates = [[storedLocalObjectStates objectForKey:accountName]
+ objectForKey:pithosContainer.name];
PithosLocalObjectState *storedState = [containerStoredLocalObjectStates objectForKey:object.name];
// Remote updated info
NSError *remoteError;
objectName:object.name
error:&remoteError
isDirectory:&remoteIsDirectory
- sharingAccount:nil];
+ 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 pithosContainer:pithosContainer]) {
+ 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)",
}
NSLog(@"Sync::create local directory object: %@", filePath);
BOOL directoryCreated = NO;
- if (!fileExists || (!isDirectory && [self moveToTempTrashFile:filePath pithosContainer:pithosContainer])) {
+ 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) {
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
message:[NSString stringWithFormat:@"Sync: Creating directory '%@/%@' locally (finished)",
- pithosContainer.name, object.name]
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
pithosAccount:pithosAccount];
});
} else if (object.bytes == 0) {
}
NSLog(@"Sync::create local zero length object: %@", filePath);
BOOL fileCreated = NO;
- if (!fileExists || ((isDirectory || [PithosUtilities bytesOfFile:filePath]) && [self moveToTempTrashFile:filePath pithosContainer:pithosContainer])) {
+ 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;
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
- pithosContainer.name, object.name]
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
pithosAccount:pithosAccount];
});
} else if (storedState.tmpFilePath == nil) {
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
- pithosContainer.name, object.name]
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
pithosAccount:pithosAccount];
});
} else {
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:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (0%%)",
- pithosContainer.name, object.name]
+ message:[messagePrefix stringByAppendingString:@" (0%%)"]
totalBytes:object.bytes
currentBytes:0
pithosAccount:pithosAccount];
[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",
- [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)", pithosContainer.name, object.name], @"finishedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(downloadObjectBlockFinished:)), @"didFinishSelector",
nil];
[objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (%.0f%%)",
- objectRequest.containerName,
- [[objectRequest.userInfo objectForKey:@"pithosObject"] name],
- (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
+ messagePrefix, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
totalBytes:activity.totalBytes
currentBytes:(activity.currentBytes + size)];
}];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
- pithosContainer.name, object.name]
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name],
+ object.name]
pithosAccount:pithosAccount];
});
} else {
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:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (0%%)",
- pithosContainer.name, object.name]
+ message:[messagePrefix stringByAppendingString:@" (0%%)"]
totalBytes:object.bytes
currentBytes:0
pithosAccount:pithosAccount];
[activityFacility updateActivity:activity withMessage:activity.message];
});
objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ accountName, @"accountName",
pithosContainer, @"pithosContainer",
object, @"pithosObject",
+ messagePrefix, @"messagePrefix",
filePath, @"filePath",
activity, @"activity",
- [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)", pithosContainer.name, object.name], @"finishedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(downloadObjectHashMapFinished:)), @"didFinishSelector",
-(void)updateServerStateWithCurrentState:(PithosLocalObjectState *)currentState
object:(ASIPithosObject *)object
localFilePath:(NSString *)filePath
+ accountName:(NSString *)accountName
pithosContainer:(ASIPithosContainer *)pithosContainer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self syncOperationStarted];
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
+ [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];
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:[NSString stringWithFormat:@"Sync: Creating directory '%@/%@'",
- pithosContainer.name, object.name]
+ 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",
- [NSString stringWithFormat:@"Sync: Creating directory '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Creating directory '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Creating directory '%@/%@' (finished)", pithosContainer.name, object.name], @"finishedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector",
[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;
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:[NSString stringWithFormat:@"Sync: Deleting '%@/%@'",
- pithosContainer.name, object.name]
+ 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",
- [NSString stringWithFormat:@"Sync: Deleting '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Deleting '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Deleting '%@/%@' (finished)", pithosContainer.name, object.name], @"finishedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(deleteObjectFinished:)), @"didFinishSelector",
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:[NSString stringWithFormat:@"Sync: Moving to trash '%@/%@'",
- pithosContainer.name, object.name]
+ 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",
- [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@' (finished)", pithosContainer.name, object.name], @"finishedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(moveObjectToTrashFinished:)), @"didFinishSelector",
}
} 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 to me" skip
+ [self syncOperationFinishedWithSuccess:YES];
+ [pool drain];
+ 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];
forFile:filePath
checkIfExists:NO
hashes:&hashes
- sharingAccount:nil];
+ 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:[NSString stringWithFormat:@"Sync: Uploading '%@/%@' (0%%)",
- pithosContainer.name, object.name]
+ message:[messagePrefix stringByAppendingString:@" (0%%)"]
totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
currentBytes:0
pithosAccount:pithosAccount];
});
[(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
[NSDictionary dictionaryWithObjectsAndKeys:
+ accountName, @"accountName",
pithosContainer, @"pithosContainer",
object, @"pithosObject",
+ messagePrefix, @"messagePrefix",
filePath, @"filePath",
hashes, @"hashes",
[NSNumber numberWithUnsignedInteger:10], @"iteration",
activity, @"activity",
- [NSString stringWithFormat:@"Sync: Uploading '%@' (stopped)", object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Uploading '%@' (failed)", object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Uploading '%@' (100%%)", object.name], @"finishedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (100%%)"], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector",
NSLog(@"Sync::list request finished: %@", containerRequest.url);
if (operation.isCancelled) {
[self listRequestFailed:containerRequest];
- } else if ((containerRequest.responseStatusCode == 200) || (containerRequest.responseStatusCode == 304)) {
+ } 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 addObjectsFromArray:someObjects];
}
if ([someObjects count] < 10000) {
- ASIPithosContainer *pithosContainer = [pithosContainers objectAtIndex:containersIndex];
pithosContainer.blockHash = [containerRequest blockHash];
pithosContainer.blockSize = [containerRequest blockSize];
pithosContainer.lastModified = [containerRequest lastModified];
for (ASIPithosObject *object in objects) {
[containerRemoteObjects setObject:object forKey:object.name];
}
- [remoteObjects setObject:containerRemoteObjects forKey:pithosContainer.name];
+ [[remoteObjects objectForKey:accountName] setObject:containerRemoteObjects forKey:pithosContainer.name];
[objects release];
objects = nil;
} else {
// Do an additional request to fetch more objects
ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
- containerName:[[pithosContainers objectAtIndex:containersIndex] name]
+ containerName:pithosContainer.name
limit:0
marker:[[someObjects lastObject] name]
prefix:nil
meta:nil
shared:NO
until:nil
- ifModifiedSince:[[pithosContainers objectAtIndex:containersIndex] lastModified]];
+ ifModifiedSince:pithosContainer.lastModified];
+ if (![accountName isEqualToString:@""])
+ [newContainerRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
newContainerRequest.delegate = self;
newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
[pool drain];
return;
}
- } else {
- ASIPithosContainer *pithosContainer = [pithosContainers objectAtIndex:containersIndex];
- NSMutableDictionary *containerRemoteObjects = [previousRemoteObjects objectForKey:pithosContainer.name];
+ } else if (containerRequest.responseStatusCode == 304) {
+ NSMutableDictionary *containerRemoteObjects = [[previousRemoteObjects objectForKey:accountName]
+ objectForKey:pithosContainer.name];
if (containerRemoteObjects)
- [remoteObjects setObject:containerRemoteObjects forKey:pithosContainer.name];
+ [[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 < containersCount) {
+ 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:[[pithosContainers objectAtIndex:containersIndex] name]
+ containerName:pithosContainer.name
limit:0
marker:nil
prefix:nil
meta:nil
shared:NO
until:nil
- ifModifiedSince:[[pithosContainers objectAtIndex:containersIndex] lastModified]];
+ ifModifiedSince:pithosContainer.lastModified];
+ if (![accountName isEqualToString:@""])
+ [newContainerRequest setRequestUserFromDefaultTo:accountName withPithos:pithos];
newContainerRequest.delegate = self;
newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
// 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 (ASIPithosContainer *pithosContainer in pithosContainers) {
- NSString *containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
- NSArray *containerExcludedDirectories = [containersDictionary objectForKey:pithosContainer.name];
- BOOL containerExludeRootFiles = [containerExcludedDirectories containsObject:@""];
- NSMutableDictionary *containerStoredLocalObjectStates = [storedLocalObjectStates 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;
- }
+ for (NSString *accountName in accountsNames) {
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
+ NSArray *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;
+ }
- 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(), ^{
- [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
- 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;
+ 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(), ^{
+ [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
+ 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;
+ }
+ }
+ // 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;
}
// Add an empty stored state for legal new remote objects since last sync
- for (ASIPithosContainer *pithosContainer in pithosContainers) {
- NSArray *containerExcludedDirectories = [containersDictionary objectForKey:pithosContainer.name];
- BOOL containerExludeRootFiles = [containerExcludedDirectories containsObject:@""];
- NSMutableDictionary *containerStoredLocalObjectStates = [storedLocalObjectStates objectForKey:pithosContainer.name];
- NSMutableDictionary *containerRemoteObjects = [remoteObjects objectForKey:pithosContainer.name];
- for (NSString *objectName in containerRemoteObjects) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self saveLocalState];
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ for (NSString *accountName in accountsNames) {
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ NSArray *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;
+ 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];
}
- if (![containerStoredLocalObjectStates objectForKey:object.name])
- [containerStoredLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:object.name];
+ [self saveLocalState];
}
- [self saveLocalState];
}
if (operation.isCancelled) {
// 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 (ASIPithosContainer *pithosContainer in pithosContainers) {
- NSString *containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
- NSArray *containerExcludedDirectories = [containersDictionary objectForKey:pithosContainer.name];
- BOOL containerExludeRootFiles = [containerExcludedDirectories containsObject:@""];
- NSMutableDictionary *containerStoredLocalObjectStates = [storedLocalObjectStates objectForKey:pithosContainer.name];
- NSMutableDictionary *containerRemoteObjects = [remoteObjects objectForKey:pithosContainer.name];
- for (NSString *objectName in [[containerStoredLocalObjectStates allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ for (NSString *accountName in accountsNames) {
+ for (ASIPithosContainer *pithosContainer in [accountsPithosContainers objectForKey:accountName]) {
+ NSString *containerDirectoryPath = [self dirPathForAccount:accountName container:pithosContainer.name];
+ NSArray *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;
+ }
- 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;
+ 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;
+ }
}
+ // 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];
}
- // 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;
+ 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;
+ }
}
- }
- 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 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];
- }
+ 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];
+ }
} else {
// Local state has changed
if (!serverStateHasChanged) {
object.contentType = @"application/directory";
else
object.objectHash = currentLocalObjectState.hash;
- [self updateServerStateWithCurrentState:currentLocalObjectState
- object:object
- localFilePath:filePath
- pithosContainer:pithosContainer];
+ [self updateServerStateWithCurrentState:currentLocalObjectState object:object localFilePath:filePath
+ accountName:accountName pithosContainer:pithosContainer];
} else {
// Server state has also changed
if (remoteObjectState.isDirectory && currentLocalObjectState.isDirectory) {
if (![remoteObjectState exists]) {
// Remote object has been deleted
informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified locally, while it has been deleted from server.",
- pithosContainer.name, object.name ];
+ [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.",
- pithosContainer.name, object.name];
+ [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.",
- pithosContainer.name, object.name];
+ [self relativeDirPathForAccount:accountName container:pithosContainer.name], object.name];
firstButtonText = @"Keep server version";
secondButtonText = @"Keep local version";
}
object.version = remoteObject.version;
object.contentType = remoteObject.contentType;
object.objectHash = remoteObject.objectHash;
- [self updateLocalStateWithObject:object localFilePath:filePath pithosContainer:pithosContainer];
+ [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
- pithosContainer:pithosContainer];
+ [self updateServerStateWithCurrentState:currentLocalObjectState object:object localFilePath:filePath
+ accountName:accountName pithosContainer:pithosContainer];
}
}
}
}
}
}
+ }
[self syncOperationFinishedWithSuccess:YES];
} else {
[self listRequestFailed:containerRequest];
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];
return;
}
- PithosLocalObjectState *storedState = [[storedLocalObjectStates objectForKey:pithosContainer.name] objectForKey:object.name];
+ 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];
storedState.tmpFilePath = tempFilePath;
[self saveLocalState];
}
-
NSUInteger missingBlockIndex = [[objectRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
NSFileHandle *tempFileHandle = [NSFileHandle fileHandleForWritingAtPath:storedState.tmpFilePath];
if (missingBlockIndex == NSNotFound) {
NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
NSString *dirPath = [filePath stringByDeletingLastPathComponent];
- if ([fileManager fileExistsAtPath:filePath] && ![self moveToTempTrashFile:filePath pithosContainer:pithosContainer]) {
+ 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"]];
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:);
[(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:@"Sync: Downloading '%@/%@' (%.0f%%)",
- newObjectRequest.containerName, object.name,
+ 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)];
if (newSyncRequested || syncLate || 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:pithosContainer.name] objectForKey:object.name];
+ 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"];
NSUInteger missingBlockIndex = [missingBlocks firstIndex];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (%.0f%%)",
- pithosContainer.name, object.name,
+ 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)];
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:);
[(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:@"Sync: Downloading '%@/%@' (%.0f%%)",
- newObjectRequest.containerName, object.name,
+ 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)];
if (operation.isCancelled) {
[self requestFailed:objectRequest];
} else if (objectRequest.responseStatusCode == 201) {
- PithosLocalObjectState *storedState = [[storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ 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];
if (operation.isCancelled) {
[self requestFailed:objectRequest];
} else if (objectRequest.responseStatusCode == 201) {
- [[storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ [[[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(), ^{
if (operation.isCancelled) {
[self requestFailed:objectRequest];
} else if (objectRequest.responseStatusCode == 204) {
- [[storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ [[[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(), ^{
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:pithosContainer.name] objectForKey:object.name];
+ 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;
currentBytes = totalBytes - [missingBlocks count]*pithosContainer.blockSize;
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@/%@' (%.0f%%)",
- pithosContainer.name, object.name, (100*(currentBytes + 0.0)/(totalBytes + 0.0))]
+ withMessage:[NSString stringWithFormat:@"%@ (%.0f%%)",
+ [objectRequest.userInfo objectForKey:@"messagePrefix"],
+ (100*(currentBytes + 0.0)/(totalBytes + 0.0))]
totalBytes:totalBytes
currentBytes:currentBytes];
});
blockSize:pithosContainer.blockSize
forFile:[objectRequest.userInfo objectForKey:@"filePath"]
missingBlockIndex:missingBlockIndex
- sharingAccount:nil];
+ sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
newContainerRequest.delegate = self;
newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
[(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:@"Sync: Uploading '%@/%@' (%.0f%%)",
- newContainerRequest.containerName, object.name, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ 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)];
}];
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"];
forFile:[containerRequest.userInfo objectForKey:@"filePath"]
checkIfExists:NO
hashes:&hashes
- sharingAccount:nil];
+ sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
newObjectRequest.delegate = self;
newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
blockSize:pithosContainer.blockSize
forFile:[containerRequest.userInfo objectForKey:@"filePath"]
missingBlockIndex:missingBlockIndex
- sharingAccount:nil];
+ sharingAccount:([accountName isEqualToString:@""] ? nil : accountName)];
newContainerRequest.delegate = self;
newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
[(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:@"Sync: Uploading '%@/%@' (%.0f%%)",
- newContainerRequest.containerName, object.name, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ 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)];
}];