Question

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

Was it helpful?

Solution

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.

OTHER TIPS

How about NSFileManager's replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:?

See documentation here

I’d suggest the FSExchangeObjects, PBExchangeObjectsSync or PBExchangeObjectsAsync functions, since they actually swap the contents of two files atomically.

From the development library:

The function allows programs to implement a “safe save” operation by creating and writing a complete new file and swapping the contents.

After the exchange, the access path will refer to the opposite file’s data (that is, to the same data it originally referred, which is now part of the other file).

Available in Mac OS X v10.0 and later.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top