用于执行Carbon FSExchangeObjectsCompat调用的Cocoa方法是什么?

问题描述:

旧的MoreFilesX,FSExchangeObjectsCompat中有这样一个功能,即“在两个文件之间交换数据”。它通常用作安全保存方法的一部分,在该方法中写入临时文件,然后调用FSExchangeObjectsCompat将新保存的临时文件与旧的“原始”文件进行交换。它保留了所有的元数据,特权等用于执行Carbon FSExchangeObjectsCompat调用的Cocoa方法是什么?

我看到高Sierra上的这个函数在APFS卷上出现故障,这在HFS +卷上从未失败。没有什么大惊喜 - 其中很多电话都被弃用了。

但是做同样的事情的Cocoa NSFileManager方法是什么?

您可以使用较低级别的功能做类似的事情。这是我写的与10.12之前的SDK一起使用的代码。如果您针对10.12 SDK或更高版本进行编译,则可以使其更简单,如果您的部署目标为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; 
} 

+0

只是要清楚 - 虽然这是首选的方法,但它实际上并没有将replaceItemAtURL与withItemAtURL“交换”。完成此操作后,原始文件将位于同一目录下的backupItemName中,然后需要与withItemAtURL交换以实现与FSExchangeObjectsCompat()相同的功能,对吧? – SMGreenfield

+0

提供'backupItemName'是可选的。如果您没有通过该选项或选项,那么实施可能(并可能)执行您正在寻找的交易类型。 –

+0

为了将来的参考 - withItemAtURL上的“new”文件在替换replaceItemAtURL处的文件后始终为DELETED。 replaceItemAtURL中的“原始”文件将被复制到backupItemName(如果提供),并且也将被删除,除非指定了NSFileManagerItemReplacementWithoutDeletingBackupItem选项标志。所以这与交易所不完全相同,但似乎足够接近。不确定这是优于还是偏好在10.12或更高版本上使用renamex_np或APFS存在时。 – SMGreenfield