Что такое метод Какао для выполнения вызова Carbon FSExchangeObjectsCompat?

В старом MoreFilesX, FSExchangeObjectsCompat, была замечательная функция, которая "обменивается данными между двумя файлами". Обычно он использовался как часть подхода безопасного сохранения, когда записывался временный файл, а затем вызывался FSExchangeObjectsCompat для обмена вновь сохраненным временным файлом со старым "оригинальным" файлом. Сохранены все метаданные, привилегии и т. Д.

Я вижу сбой с этой функцией в High Sierra, на томах APFS, который никогда не выходил из строя на томах HFS+. Не большой сюрприз - многие из этих вызовов устарели.

Но что такое метод Cocoa NSFileManager, позволяющий сделать то же самое?

2 ответа

Решение

Вы можете сделать что-то подобное, используя функции более низкого уровня. Вот код, который я написал для использования с SDK до 10.12. Вы можете сделать это несколько проще, если компилируете с использованием SDK 10.12 или новее, и еще проще, если у вас есть цель развертывания 10.12 или новее.

#ifndef RENAME_SWAP
#define RENAME_SWAP    0x00000002
#endif

/*!
    @function   ExchangeFiles

    @abstract   Given full paths to two files on the same volume,
                swap their contents.

    @discussion This is often part of a safe-save strategy.

    @param      inOldFile   Full path to a file.
    @param      inNewFile   Full path to a file.
    @result     0 if all went well, -1 otherwise.
*/
int ExchangeFiles( const char* inOldFile, const char* inNewFile )
{
    int result = -1;
    static dispatch_once_t sOnce = 0;
    static renameFuncType sRenameFunc = NULL;
    // Try to get a function pointer to renamex_np, which is available in OS 10.12 and later.
    dispatch_once( &sOnce,
        ^{
            sRenameFunc = (renameFuncType) dlsym( RTLD_DEFAULT, "renamex_np" );
        });

    // renamex_np is only available on OS 10.12 and later, and does not work on HFS+ volumes
    // but does work on APFS volumes.  Being the latest and greatest, we try it first.
    if (sRenameFunc != NULL)
    {
        result = (*sRenameFunc)( inOldFile, inNewFile, RENAME_SWAP );
    }

    if (result != 0)
    {
        // exchangedata is an older function that works on HFS+ but not APFS.
        result = exchangedata( inOldFile, inNewFile, 0 );
    }

    if (result != 0)
    {
        // Neither function worked, we must go old school.
        std::string nameTemplate( inOldFile );
        nameTemplate += "-swapXXXX";
        // Make a mutable copy of the template
        std::vector<char>   workPath( nameTemplate.size() + 1 );
        memcpy( &workPath[0], nameTemplate.c_str(), nameTemplate.size() + 1 );
        mktemp( &workPath[0] );
        std::string tempPath( &workPath[0] );

        // Make the old file have a temporary name
        result = rename( inOldFile, tempPath.c_str() );

        // Put the new file data under the old name.
        if (result == 0)
        {
            result = rename( inNewFile, inOldFile );
        }

        // Put the old data under the new name.
        if (result == 0)
        {
            result = rename( tempPath.c_str(), inNewFile );
        }
    }

    return result;
}

Ты хочешь -[NSFileManager replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:],

Другие вопросы по тегам