How to find out if PBXLockRange() and file locking would work on a given volume in 64bit carbon?

51 views Asked by At

Well, I know Carbon is deprecated but some of it still works and provides functionality not present in Cocoa or Core Foundation.

One of the parts of the Carbon that survived 64bit transition handles file range locking. The functions PBXLockRangeSync() and PBXLockRange() have this remark in documentation:

Lock a range of bytes of the file fork specified by forkRefNum. This is only supported on some volume formats.

I've been testing it and in fact, they don't work on local file systems but do work on shares. So far I have tested this call only on two afp shares and it worked well. Changing the same file from two different computers did not corrupt the file. On local volume functions return an error like not implemented.

I wonder if maybe someone with this 'ancient' knowledge of macOS programming has any idea if I can test a file system weather it supports this feature?

So far I am very confused as I have found Tech Note by Apple and the code to test if a volume supports file locks. Well, it returns exact opposite of where PBXLockRange() does work. Gives me TRUE on my local disk but FALSE for a shared volume where PBXLockRange() does work.

The code for testing if a volume supports file locks, from that link but modified for a function that exists in 64bit Carbon. (I tested the original version on an older Mac OS in 32bit code and they behave the same.)

#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);
}

Plus, I wanted to check if a volume is a share. No luck with FSGetVolumeParms() as vMAttrib or vMExtendedAttributes of GetVolParmsInfoBuffer don't have anything that looks like a 'shared volume' flag.

edit - I found out about NSURL method -getResourceValue:forKey:error: with NSURLVolumeIsLocalKey so this solves the second question.

edit 2:

Next day I found about NSURLVolumeSupportsAdvisoryFileLockingKey and using that with -getResourceValue:forKey:error: is consistent with all other methods - value is positive when I can't have locks and negative when I can.

In the end, this is how I'll check if a volume is a shared one in both 32bit and 64bit 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);
}

All of this is the same on both AFP and SMB shares. Locking works fine even when I mix them from two different client computers. Tested on one Mac OS server and later on Synology NAS. It would be interesting if I try one Windows client in the mix.

0

There are 0 answers