+- (BOOL)moveNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode {
+ if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) ||
+ (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"]))
+ return NO;
+ NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name];
+ NSString *objectNamePrefix;
+ if ([destinationNode class] == [PithosSubdirNode class])
+ objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name];
+ else
+ objectNamePrefix = [NSString string];
+
+ for (PithosNode *node in nodes) {
+ if (([node class] == [PithosObjectNode class]) ||
+ (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
+ // Operation: Move an object or subdir/ node
+ __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
+ @autoreleasepool {
+ if (operation.isCancelled)
+ return;
+ NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if ([node.pithosObject.name hasSuffix:@"/"])
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos
+ containerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES];
+ if (!operation.isCancelled && objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'",
+ [objectRequest.userInfo objectForKey:@"sourceContainerName"],
+ [objectRequest.userInfo objectForKey:@"sourceObjectName"],
+ [objectRequest.userInfo objectForKey:@"destinationContainerName"],
+ [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove
+ message:messagePrefix];
+ [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ moveNetworkQueue, @"networkQueue",
+ @"move", @"operationType",
+ nil]];
+ [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ }
+ }
+ }];
+ [moveQueue addOperation:operation];
+ } else if ([node class] == [PithosSubdirNode class]) {
+ // Operation: Move a subdir node and its descendants
+ // The resulting ASIPithosObjectRequests are chained through dependencies
+ __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
+ @autoreleasepool {
+ if (operation.isCancelled)
+ return;
+ NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if (node.pithosObject.subdir)
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithos
+ containerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES];
+ if (!operation.isCancelled && objectRequests) {
+ ASIPithosObjectRequest *previousObjectRequest = nil;
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+ if (operation.isCancelled)
+ return;
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'",
+ [objectRequest.userInfo objectForKey:@"sourceContainerName"],
+ [objectRequest.userInfo objectForKey:@"sourceObjectName"],
+ [objectRequest.userInfo objectForKey:@"destinationContainerName"],
+ [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove
+ message:messagePrefix];
+ [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes",
+ [NSNumber numberWithBool:YES], @"refresh",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ moveNetworkQueue, @"networkQueue",
+ @"move", @"operationType",
+ nil]];
+ if (previousObjectRequest)
+ [objectRequest addDependency:previousObjectRequest];
+ previousObjectRequest = objectRequest;
+ [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ }
+ }
+ }
+ }];
+ [moveQueue addOperation:operation];
+ }
+ }
+ return YES;
+}
+
+- (BOOL)cpyNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode {
+ if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) ||
+ (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"]))
+ return NO;
+ NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name];
+ NSString *objectNamePrefix;
+ if ([destinationNode class] == [PithosSubdirNode class])
+ objectNamePrefix = [NSString stringWithString:destinationNode.pithosObject.name];
+ else
+ objectNamePrefix = [NSString string];
+
+ for (PithosNode *node in nodes) {
+ if (([node class] == [PithosObjectNode class]) ||
+ (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
+ // Operation: Copy an object or subdir/ node
+ __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
+ @autoreleasepool {
+ if (operation.isCancelled)
+ return;
+ NSString *destinationObjectName;
+ if (![destinationNode isEqualTo:node.parent]) {
+ destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if ([node.pithosObject.name hasSuffix:@"/"])
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ } else {
+ destinationObjectName = [PithosUtilities safeObjectNameForPithos:pithos
+ containerName:containerName
+ objectName:node.pithosObject.name];
+ }
+ if (operation.isCancelled)
+ return;
+ ASIPithosObjectRequest *objectRequest = [PithosUtilities cpyObjectRequestWithPithos:pithos
+ containerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES
+ sharingAccount:node.sharingAccount];
+ if (!operation.isCancelled && objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'",
+ [objectRequest.userInfo objectForKey:@"sourceContainerName"],
+ [objectRequest.userInfo objectForKey:@"sourceObjectName"],
+ [objectRequest.userInfo objectForKey:@"destinationContainerName"],
+ [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy
+ message:messagePrefix];
+ [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(copyFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ copyNetworkQueue, @"networkQueue",
+ @"copy", @"operationType",
+ nil]];
+ [copyNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ }
+ }
+ }];
+ [copyQueue addOperation:operation];
+ } else if ([node class] == [PithosSubdirNode class]) {
+ // Operation: Copy a subdir node and its descendants
+ // The resulting ASIPithosObjectRequests are chained through dependencies
+ __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
+ @autoreleasepool {
+ if (operation.isCancelled)
+ return;
+ NSString *destinationObjectName;
+ if (![destinationNode isEqualTo:node.parent]) {
+ destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
+ if (node.pithosObject.subdir)
+ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
+ } else {
+ destinationObjectName = [PithosUtilities safeSubdirNameForPithos:pithos
+ containerName:containerName
+ subdirName:node.pithosObject.name];
+ }
+ if (operation.isCancelled)
+ return;
+ NSArray *objectRequests = [PithosUtilities cpyObjectRequestsForSubdirWithPithos:pithos
+ containerName:node.pithosContainer.name
+ objectName:node.pithosObject.name
+ destinationContainerName:containerName
+ destinationObjectName:destinationObjectName
+ checkIfExists:YES
+ sharingAccount:node.sharingAccount];
+ if (!operation.isCancelled && objectRequests) {
+ ASIPithosObjectRequest *previousObjectRequest = nil;
+ for (ASIPithosObjectRequest *objectRequest in objectRequests) {
+ if (operation.isCancelled)
+ return;
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ NSString *messagePrefix = [NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'",
+ [objectRequest.userInfo objectForKey:@"sourceContainerName"],
+ [objectRequest.userInfo objectForKey:@"sourceObjectName"],
+ [objectRequest.userInfo objectForKey:@"destinationContainerName"],
+ [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy
+ message:messagePrefix];
+ [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes",
+ activity, @"activity",
+ [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage",
+ [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(copyFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ copyNetworkQueue, @"networkQueue",
+ @"copy", @"operationType",
+ nil]];
+ if (previousObjectRequest)
+ [objectRequest addDependency:previousObjectRequest];
+ previousObjectRequest = objectRequest;
+ [copyNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ }
+ }
+ }
+ }];
+ [copyQueue addOperation:operation];
+ }
+ }
+ return YES;