Created
February 7, 2013 01:11
-
-
Save tjw/4727528 to your computer and use it in GitHub Desktop.
Test case for Radar 13167947.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
/* | |
clang -fobjc-arc -O2 -Wall write-file-by-merging.m -o write-file-by-merging -framework Foundation | |
echo qq > $HOME/Desktop/qq.txt | |
open -e $HOME/Desktop/qq.txt | |
then: | |
date > /tmp/d; ./write-file-by-merging /tmp/d $HOME/Desktop/qq.txt | |
TextEdit doesn't show the updated contents. | |
This is *very* sensitive to timing or filesystem access in the _checkURL() function: | |
* If either of the #if blocks in _pokeFile() are changed from #if 1 to #if 0, it works. | |
* If the sleep(1) is uncommented right before the NSFileManager -replaceItemAtURL:... call (inside the coordinator block), it works. | |
This happens on a variety of machines at Omni, but most are Retina MacBook Pro. System profile attached to Radar. | |
*/ | |
BOOL _pokeFile(NSURL *fileURL, NSError **outError) | |
{ | |
#if 1 | |
NSError *error = nil; | |
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:outError]; | |
if (!attributes) { | |
NSLog(@"Error getting attributes of %@: %@", fileURL, error); | |
if (outError) | |
*outError = error; | |
return NO; | |
} | |
#endif | |
#if 1 | |
NSData *fileData = [[NSData alloc] initWithContentsOfURL:fileURL options:NSDataReadingMappedIfSafe|NSDataReadingUncached error:outError]; | |
if (!fileData) | |
abort(); | |
#endif | |
return YES; | |
} | |
static BOOL _checkURL(NSURL *localDocumentURL, NSFileCoordinator *coordinator, NSFileCoordinatorReadingOptions options) | |
{ | |
__block BOOL success; | |
__block NSError *error; | |
[coordinator coordinateReadingItemAtURL:localDocumentURL options:options error:&error byAccessor: | |
^(NSURL *newReadingURL) { | |
// We don't actually check anything in this sample app. | |
success = _pokeFile(newReadingURL, &error); | |
}]; | |
return success; | |
} | |
static BOOL _writeFileByMerging(NSURL *sourceURL, NSURL *destURL, NSError **outError) | |
{ | |
// We treat 'sourceURL' as if it doesn't need file coordination (it is our private copy). | |
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil]; | |
__block NSError *error; | |
__block BOOL success = NO; | |
[coordinator prepareForReadingItemsAtURLs:nil options:0 | |
writingItemsAtURLs:@[destURL] options:0/*don't know what we are going to do yet*/ | |
error:&error byAccessor: | |
^(void (^completionHandler)(void)){ | |
// Make cleanup easier... | |
if (!completionHandler) | |
completionHandler = ^{}; | |
// Do a read of the source to see if it has changed, w/o claiming we'll do any write above. | |
__block BOOL validateSuccess = NO; | |
[coordinator coordinateReadingItemAtURL:destURL options:0 error:&error byAccessor:^(NSURL *newURL) { | |
validateSuccess = _checkURL(destURL, coordinator, 0); | |
}]; | |
if (!validateSuccess) { | |
NSLog(@"destination changed"); | |
completionHandler(); | |
return; | |
} | |
[coordinator coordinateWritingItemAtURL:destURL options:NSFileCoordinatorWritingForMerging error:&error byAccessor:^(NSURL *newURL) { | |
//sleep(1); | |
if (![[NSFileManager defaultManager] replaceItemAtURL:newURL withItemAtURL:sourceURL backupItemName:nil options:0 resultingItemURL:NULL error:&error]) | |
return; | |
success = YES; | |
}]; | |
completionHandler(); | |
success = YES; | |
}]; | |
if (!success && outError) | |
*outError = error; | |
return success; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if (argc != 3) { | |
fprintf(stderr, "usage: %s src dest\n", argv[0]); | |
exit(1); | |
} | |
@autoreleasepool { | |
NSURL *sourceURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:argv[1]]]; | |
NSURL *destURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:argv[2]]]; | |
NSError *error; | |
if (!_writeFileByMerging(sourceURL, destURL, &error)) | |
NSLog(@"Error: %@", error); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment