In a cocoa app of mine, there is a method that does some operations on a sqlite database's schema that could be destructive, so first we make a rollback copy of the database, and if there's an error, we call the following method to replace the db file with the rollback file. Note that I definitely want the db file replaced with the rollback!
- (BOOL)restoreDatabaseFromFileAtPath:(NSString *)backupPath error:(NSError **)error {
NSFileManager *fm = [NSFileManager defaultManager];
// get the db paths
NSString *databasePath = [sharedManager pathToDatabase];
// insist that the two files be present
NSAssert1([fm fileExistsAtPath:databasePath], @"no db file at %@", databasePath);
NSAssert1([fm fileExistsAtPath:backupPath], @"no backup db file at %@", backupPath);
// remove the original to make way for the backup
NSLog(@"removing the file at the primary database path...");
if ([fm removeItemAtPath:databasePath error:error]) {
// now move the backup to the original location
NSLog(@"moving the backup file into the primary database path...");
if ([fm moveItemAtPath:backupPath toPath:databasePath error:error]) {
return YES;
}
}
[self presentError:error]; // at this point we're in real trouble
return NO;
}
The code shown does work, but it's potentially very destructive and not exactly atomic. What I would really like to do is something that I imagine exists, but I can't find a way to do it in the API for NSFileManager, something like:
Bool success = [fm moveFileAtPath:backupPath toPath:databasePath overwriteDestination:YESPLZ error:&error];
The method that comes closest to this barfs when it discovers there's already a file at the destination path.
Small update based on responses so far:
There's got to be some standard way this has traditionally been done by Cocoa devs, to atomically replace a file. The various 'move' methods of NSFileManager don't provide a facility for this out of the box. Also, looking to support 10.5 and up in this lib as well as iPhone OS 3+.