R – How to safely move / swap files in Cocoa

cocoamacosnsfilemanager

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+.

Best Answer

The C-level FSMoveObjectSync/FSMoveObjectAsync functions might help. These functions take a set of options, which can include a flag to overwrite the destination, kFSFileOperationOverwrite, among other things.