Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Files /
Chapter 2 - File Manager / Using the File Manager


Locking and Unlocking File Ranges

A file can be opened with shared read/write permission to allow several users to share the data in the file. When a user needs to modify a portion of a file that has been opened with shared read/write permission, it is usually desirable to make that portion of the file unavailable to other users while the changes are made. You can call the PBLockRange function to lock a range of bytes before modifying the file and then PBUnlockRange to unlock that range after your changes are safely recorded in the file.

Locking a range of bytes in a file gives the user exclusive read/write access to that range and makes it inaccessible to other users. Other users can neither write nor read the bytes in that range until you unlock it. If other users attempt to read data from a portion of a file that you have locked, they receive the fLckdErr result code.

The functions PBLockRange and PBUnlockRange are effective only on files that are located on volumes that are sharable. If you call PBLockRange on a file that is not located on a remote server volume or that is not currently being shared, no range locking occurs. Moreover, PBLockRange does not return a result code indicating that no range locking has occurred. As a result, you should usually check whether range locking will be effective on a file before attempting to lock the desired range.

Listing 2-9 illustrates how you can check to make sure that calling PBLockRange will have the desired effect.

Listing 2-9 Determining whether a file can have ranges locked

FUNCTION RangesCanBeLocked (fRefNum: Integer): Boolean;
VAR
   myParmBlk:  ParamBlockRec;             {basic parameter block}
   myErr:      OSErr;
BEGIN
   WITH myParmBlk DO
      BEGIN
         ioRefNum := fRefNum;
         ioReqCount := 1;                 {lock a single byte}
         ioPosMode := fsFromStart;        {at the beginning of the file}
         ioPosOffset := 0;
      END;
   myErr := PBLockRange(@myParmBlk, FALSE);{lock the byte; ignore result}
   myErr := PBLockRange(@myParmBlk, FALSE);{lock the byte again}


   CASE myErr OF
      fLckdErr,                           {byte was locked by another user}
      afpRangeOverlap,                    {byte was locked by this user}
      afpNoMoreLocks:                     {max number of locks already used}
         BEGIN
            RangesCanBeLocked := TRUE;    {range locking is supported}
            IF myErr = afpRangeOverlap THEN  {unlock the byte we locked}
               myErr := PBUnlockRange(@myParmBlk, FALSE);
         END;
      OTHERWISE
         RangesCanBeLocked := FALSE;      {range locking is not supported}
   END; {of CASE}
END;
The function RangesCanBeLocked takes a file reference number of an open file as
a parameter; this is the reference number of the file in which a range of bytes is to
be locked. The function attempts to locks the first byte in the file and immediately
attempts to lock it again. If the second range locking fails with the result code afpRangeOverlap, the first call to PBLockRange was successful. If the second call to PBLockRange fails with the result code fLckdErr, the byte was already locked by another user. Similarly, if the second call to PBLockRange fails with the result code afpNoMoreLocks, the maximum number of range locks has been reached. In these three cases, range locking is supported by the volume containing the specified file. If any other result code (including noErr) is returned, range locking is not supported by that volume or for some reason the capabilities of the volume cannot be determined.

Note
Local file sharing can be started or stopped (via the Sharing Setup control panel) while your application is running. For this reason, each time you want to lock a range, it's best to check that byte ranges in that file can be locked.
You can unlock a locked range of bytes by calling PBUnlockRange. Note that the range to be unlocked must be the exact same range of bytes that was previously locked using PBLockRange. (You can lock and unlock different byte ranges in any order, however.) If for some reason you need to unlock a range of bytes and do not know where the range started or how long the range is, you must close the file to unlock the range. When a file is closed, all locked ranges held by a user are unlocked.

If you want to append data to a shared file, you can use PBLockRange to lock the range of bytes from the file's current logical end-of-file to the last possible addressable byte of the file. Once you have locked that range, you can write data into it. Listing 2-10 shows how to determine the current logical end-of-file and lock the appropriate range.

Listing 2-10 Locking a file range to append data to the file

FUNCTION LockRangeForAppending (fRefNum: Integer; VAR EOF: LongInt): OSErr;
VAR
   myParmBlk:  ParamBlockRec;             {basic parameter block}
   myErr:      OSErr;
   myEOF:      LongInt;                   {current EOF}
BEGIN
   myParmBlk.ioCompletion := NIL;
   myParmBlk.ioRefNum := fRefNum;
   myErr := PBGetEOF(@myParmBlk, FALSE);  {get the current EOF}
   IF myErr <> noErr THEN
      BEGIN
         LockRangeForAppending := myErr;
         Exit(LockRangeForAppending);     {trouble reading EOF}
      END;
   myEOF := LongInt(myParmBlk.ioMisc);    {save the current EOF}
   WITH myParmBlk DO
      BEGIN
         ioReqCount := -1;                {all addressable bytes}
         ioPosMode := fsFromStart;        {start range...}
         ioPosOffset := myEOF;            {...at the current end-of-file}
      END;
   myErr := PBLockRange(@myParmBlk, FALSE);{lock the specified range}
   EOF := myEOF;                          {return current EOF to caller}
   LockRangeForAppending := myErr;
END;
The function LockRangeForAppending first determines the current logical end-of-file. It is important to get this value immediately before you attempt to lock a range that depends on it because another user of the shared file might have changed the end-of-file since you last read it. Then LockRangeForAppending locks the range beginning at the current end-of-file and extending for the maximum number of bytes (specified using the special value -1).

In effect, this technique locks a range where data does not yet exist. Practically speaking, locking the entire addressable range of a file prevents another user from appending data to the file until you unlock that range. Note that LockRangeForAppending returns the current logical end-of-file to the caller so that the caller can unlock the correct range of bytes after appending the data.

You can also call PBLockRange to lock a range of bytes when you want to truncate a file. Locking the end portion of a file to be deleted prevents another user from using that portion during the truncation. Instead of setting the ioPosOffset field of the parameter block to the logical end-of-file (as in Listing 2-10), simply set it to what will be the last byte after the file is truncated. Similarly, you can lock an entire file fork by setting the ioPosOffset field to 0.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
2 JUL 1996