如何检测64位Carbon中PBXLockRange()及文件锁在指定卷的可用性?
我了解Carbon已被弃用,但部分功能仍可正常工作,且提供Cocoa或Core Foundation不具备的特性。其中,64位Carbon保留了处理文件范围锁的功能,PBXLockRangeSync()和PBXLockRange()函数的文档说明如下:
锁定forkRefNum指定文件分支的字节范围,仅部分卷格式支持该功能。
经测试发现,这些函数在本地文件系统无法工作,但在共享卷中可正常运行。目前已在两个AFP共享卷测试,多台电脑修改同一文件未出现损坏,本地卷调用时会返回“未实现”类错误。
我想了解是否有熟悉macOS旧版编程的开发者知晓如何检测文件系统是否支持该功能?
目前我遇到困惑:苹果技术笔记(Tech Note)中的卷文件锁支持检测代码,返回结果与PBXLockRange()的实际可用情况完全相反——本地磁盘返回TRUE,而PBXLockRange()可用的共享卷返回FALSE。以下是适配64位Carbon的检测代码(32位旧版Mac OS测试结果一致):
#ifndef gestaltFSSupportsExclusiveLocks #define gestaltFSSupportsExclusiveLocks 15 #define bSupportsExclusiveLocks 18 #endif Boolean VolumeSupportsExclusiveFileAccess (short vRefNum) { OSErr err; SInt32 response; Boolean exclusiveAccess = FALSE; err = Gestalt (gestaltFSAttr, &response); if (!err && (response & (1L << gestaltFSSupportsExclusiveLocks))) { GetVolParmsInfoBuffer vparams = { 0 }; OSStatus status = FSGetVolumeParms (vRefNum, // use default volume &vparams, // write sizeof(GetVolParmsInfoBuffer)); if (!status) exclusiveAccess = (vparams.vMExtendedAttributes & (1L << bSupportsExclusiveLocks)) != 0; } return (exclusiveAccess); }
另外,我曾尝试检测卷是否为共享卷,但FSGetVolumeParms()返回的GetVolParmsInfoBuffer中vMAttrib或vMExtendedAttributes无“共享卷”标识。
编辑:发现可通过NSURL的-getResourceValue:forKey:error:方法结合NSURLVolumeIsLocalKey解决该问题。
编辑2:后续发现NSURLVolumeSupportsAdvisoryFileLockingKey结合该方法的检测结果与其他方法一致——值为真时无法使用锁,值为假时可使用锁。
最终,我编写了可在32位和64位Carbon中检测共享卷的代码:
Boolean VolumeIsSharedVolume (short vRefNum, Boolean *supportsFileLocks) // ExclusiveFileAccess { OSErr err; SInt32 response; Boolean exclusiveLocks = FALSE; Boolean volumeIsShared = FALSE; GetVolParmsInfoBuffer volParmsBuffer = { 0 }; err = Gestalt (gestaltSystemVersion, &response); if ((err == noErr) && (response < 0x01000)) { err = Gestalt (gestaltMacOSCompatibilityBoxAttr, &response); if ((err != noErr) || ((response & (1 << gestaltMacOSCompatibilityBoxPresent)) == 0)) return (TRUE); // Running on Mac OS 9, not in Classic } err = Gestalt (gestaltFSAttr, &response); if (!err && (response & (1L << gestaltFSSupportsExclusiveLocks))) { #if __LP64__ err = FSGetVolumeParms (vRefNum, &volParmsBuffer, sizeof(GetVolParmsInfoBuffer)); #else HParamBlockRec hPB; hPB.ioParam.ioVRefNum = vRefNum; hPB.ioParam.ioNamePtr = NULL; hPB.ioParam.ioBuffer = (Ptr) &volParmsBuffer; hPB.ioParam.ioReqCount = sizeof (volParmsBuffer); err = PBHGetVolParmsSync (&hPB); #endif // __LP64__ if (!err) { exclusiveLocks = (volParmsBuffer.vMExtendedAttributes & (1L << bSupportsExclusiveLocks)) != 0; if (volParmsBuffer.vMServerAdr) volumeIsShared = TRUE; } } if (supportsFileLocks) *supportsFileLocks = exclusiveLocks; return (volumeIsShared); }
该代码在AFP和SMB共享卷中表现一致,多客户端混合修改文件时锁功能正常,已在Mac OS服务器和群晖NAS测试,后续计划加入Windows客户端测试。
内容的提问来源于stack exchange,提问作者IgorD

