Important: The information in this document is obsolete and should not be used for new development.
Searching a Volume
To search a volume efficiently, you can use thePBCatSearch
function. ThePBCatSearch
function looks at all entries in the volume's catalog file and returns a list of all files or directories that match the criteria you specify. You can askPBCatSearch
to match files or directories using many types of criteria, including
Like all low-level File Manager functions,
- names or partial names
- file and directory attributes
- Finder information
- physical and logical file length
- creation, modification, and backup dates
- parent directory ID
PBCatSearch
exchanges information with your application through a parameter block. ThePBCatSearch
function uses thecsParam
variant of the basic parameter block defined by theHParamBlockRec
data type. That variant includes two fields,ioSearchInfo1
andioSearchInfo2
, that contain the addresses of two catalog information records (of typeCInfoPBRec
). You specify which kinds of files or directories you want to search for by filling in the fields of those two records.The fields in
ioSearchInfo1
andioSearchInfo2
have different uses:
Some fields in the catalog information records apply only to files, some only to directories, and some to both. Some of the fields that apply to both have different names, depending on whether the target of the record is a file or a directory. The
- The
ioNamePtr
field inioSearchInfo1
holds a pointer to the target string; theioNamePtr
field inioSearchInfo2
must beNIL
. (If you're not searching for the name, theioNamePtr
field inioSearchInfo1
must also beNIL
.)- The date and length fields in
ioSearchInfo1
hold the lowest values in the target range, and the date and length fields inioSearchInfo2
hold the highest values in the target range. ThePBCatSearch
function looks for values greater than or equal to the field values inioSearchInfo1
and less than or equal to the values inioSearchInfo2
.- The
ioFlAttrib
andioFlFndrInfo
fields inioSearchInfo1
hold the target values, and the same fields inioSearchInfo2
hold masks that specify which bits are relevant.
PBCatSearch
function uses only some fields in the catalog information record. Table 2-11 lists the fields used for files.Table 2-12 lists the fields in catalog information records used for directories.
Table 2-12 Fields in
ioSearchInfo1
andioSearchInfo2
used for a directoryThe
PBCatSearch
function searches only on bits 0 and 4 in the file attributes
field (ioFlAttrib
).
Bit Meaning 0 Set if the file or directory is locked. 4 Set if the item is a directory.
To give
- Note
- The
PBCatSearch
function cannot use the additional bits returned in theioFlAttrib
field by thePBGetCatInfo
function.PBCatSearch
a full description of the search criteria, you pass it a pair of catalog information records that determine the limits of the search and a mask that identifies the relevant fields within the records. You pass the mask in theioSearchBits
field in thePBCatSearch
parameter block. To determine the value ofioSearchBits
, add the appropriate constants. To match all files and directories on a volume (including the volume's root directory), setioSearchBits
to 0.
CONST fsSBPartialName = 1; {substring of name} fsSBFullName = 2; {full name} fsSBFlAttrib = 4; {directory flag; software lock flag} fsSBNegate = 16384;{reverse match status} {for files only} fsSBFlFndrInfo = 8; {Finder file info} fsSBFlLgLen = 32; {logical length of data fork} fsSBFlPyLen = 64; {physical length of data fork} fsSBFlRLgLen = 128; {logical length of resource fork} fsSBFlRPyLen = 256; {physical length of resource fork} fsSBFlCrDat = 512; {file creation date} fsSBFlMdDat = 1024; {file modification date} fsSBFlBkDat = 2048; {file backup date} fsSBFlXFndrInfo = 4096; {more Finder file info} fsSBFlParID = 8192; {file's parent ID} {for directories only} fsSBDrUsrWds = 8; {Finder directory info} fsSBDrNmFls = 16; {number of files in directory} fsSBDrCrDat = 512; {directory creation date} fsSBDrMdDat = 1024; {directory modification date} fsSBDrBkDat = 2048; {directory backup date} fsSBDrFndrInfo = 4096; {more Finder directory info} fsSBDrParID = 8192; {directory's parent ID}For example, to search for a file that was created between two specified dates and whose name contains a specified string, setioSearchBits
to 517 (that is, to fsSBFlAttrib+ fsSBFlCrDat
+fsSBPartialName
).A catalog entry must meet all of the specified criteria to be placed in the list of matches. After
PBCatSearch
has completed its scan of each entry, it checks thefsSBNegate
bit. If that bit is set,PBCatSearch
reverses the entry's match status (that is, if the entry is a match but thefsSBNegate
bit is set, the entry is not put in the list of matches; if it is not a match, it is put in the list).
Although using
- Note
- The
fsSBNegate
bit is ignored during searches of remote volumes that support AFP version 2.1.PBCatSearch
is significantly more efficient than searching the directories recursively, searching a large volume can still take long enough to affect user response time. You can break a search into several shorter searches by specifying a maximum length of time in theioSearchTime
field of the parameter block and keeping an index in theioCatPosition
field. ThePBCatSearch
function stores its directory-location index in a catalog position record, which is defined by theCatPositionRec
data type.
TYPE CatPositionRec = {catalog position record} RECORD initialize: LongInt; {starting point} priv: ARRAY[1..6] OF Integer; {private data} END;To start a search at the beginning of the catalog, set theinitialize
field to 0. WhenPBCatSearch
exits because of a timeout, it updates the record so that it describes the next entry to be searched. When you callPBCatSearch
to resume the search after a timeout, pass the entire record that was returned by the last call.PBCatSearch
returns a list of the names and parent directories of all files and directories that match the criteria you specify. It places the list in an array pointed to by theioMatchPtr
field.
Listing 2-3 illustrates how to use
- Note
- The
ioSearchTime
field is not used by AFP volumes. To break up a potentially lengthy search into smaller searches on AFP volumes, use
theioReqMatchCount
field to specify the maximum number of matches to return.PBCatSearch
to find all files (not directories) whose names contain the string "Temp" and that were created within the past two days.Listing 2-3 Searching a volume with
PBCatSearch
CONST kMaxMatches = 30; {find up to 30 matches in one pass} kOptBufferSize = $4000; {use a 16K search cache for speed} VAR myErr: OSErr; {result code of function calls} myCount: Integer; {loop control variable} myFName: Str255; {name of string to look for} myVRefNum: Integer; {volume to search} myDirID: LongInt; {ignored directory ID for HGetVol} myCurrDate: LongInt; {current date, in seconds} twoDaysAgo: LongInt; {date two days ago, in seconds} myPB: HParamBlockRec; {parameter block for PBCatSearch} myMatches: PACKED ARRAY[1..kMaxMatches] OF FSSpec; {put matches here} mySpec1: CInfoPBRec; {search criteria, part 1} mySpec2: CInfoPBRec; {search criteria, part 2} myBuffer: PACKED ARRAY[1..kOptBufferSize] OF Char; {search cache} done: Boolean; {have all matches been found?} PROCEDURE SetupForFirstTime; BEGIN myErr := HGetVol(NIL, myVRefNum, myDirID); {search on the default volume} myFName := 'Temp'; {search for "Temp"} GetDateTime(myCurrDate); {get current time in seconds} twoDaysAgo := myCurrDate - (2 * 24 * 60 * 60); WITH myPB DO BEGIN ioCompletion := NIL; {no completion routine} ioNamePtr := NIL; {no volume name; use vRefNum} ioVRefNum := myVRefNum; {volume to search} ioMatchPtr := FSSpecArrayPtr(@myMatches); {points to results buffer} ioReqMatchCount:= kMaxMatches; {number of matches} ioSearchBits := fsSBPartialName {search on partial name} + fsSBFlAttrib {search on file attributes} + fsSBFlCrDat; {search on creation date} ioSearchInfo1 := @mySpec1; {points to first criteria set} ioSearchInfo2 := @mySpec2; {points to second criteria set} ioSearchTime := 0; {no timeout on searches} ioCatPosition.initialize := 0; {set hint to 0} ioOptBuffer := @myBuffer; {point to search cache} ioOptBufSize := kOptBufferSize; {size of search cache} END; WITH mySpec1 DO BEGIN ioNamePtr := @myFName; {point to string to find} ioFlAttrib := $00; {clear bit 4 to ask for files} ioFlCrDat := twoDaysAgo; {lower bound of creation date} END; WITH mySpec2 DO BEGIN ioNamePtr := NIL; {set to NIL} ioFlAttrib := $10; {set mask for bit 4} ioFlCrDat := myCurrDate; {upper bound of creation date} END; END; BEGIN SetupForFirstTime; {initialize data records} REPEAT myErr := PBCatSearchSync(@myPB); {get some files} done := (myErr = eofErr); {eofErr returned when all done} IF ((myErr = noErr) | done) & (myPB.ioActMatchCount > 0) THEN FOR myCount := 1 TO myPB.ioActMatchCount DO Writeln(myMatches[myCount].name); {report all matches found} UNTIL done; END;WhenPBCatSearch
is not available in the current operating environment or is not supported by the volume you wish to search, you'll need to usePBGetCatInfo
to perform a recursive, indexed search through the volume's directory hierarchy. This
kind of search is usually much slower than a search withPBCatSearch
, and you
can encounter problems you avoid by usingPBCatSearch
. For example, a
recursive, indexed search can require a large amount of stack space. The procedureEnumerateShell
defined in Listing 2-4 is designed to minimize the amount of stack space used. As a result, it should execute even in environments with very limited
stack space.Listing 2-4 Searching a volume using a recursive, indexed search
PROCEDURE EnumerateShell (vRefNum: Integer; dirID: LongInt); VAR myName: Str63; myCPB: CInfoPBRec; myErr: OSErr; PROCEDURE EnumerateCatalog (dirID: LongInt); CONST kFolderBit = 4; VAR index: Integer; BEGIN index := 1; REPEAT WITH myCBP DO BEGIN ioFDirIndex := index; ioDrDirID := dirID; {reset dirID; PBGetCatInfo may change it} ioACUser := 0; END; myErr := PBGetCatInfo(@myCPB, FALSE); IF myErr = noErr THEN IF BTst(myCPB.ioFlAttrib, kFolderBit) THEN BEGIN {we have a directory} {Do something useful with the dir. information in myCPB.} EnumerateCatalog(myCPB.ioDrDirID); myErr := noErr; {clear error return on way back} END ELSE BEGIN {we have a file} {Do something useful with the file information in myCPB.} END; index := index + 1; UNTIL (myErr <> noErr); END; {EnumerateCatalog} BEGIN {EnumerateShell} WITH myCPB DO BEGIN ioNamePtr := @myName; ioVRefNum := vRefNum; END; EnumerateCatalog(dirID); END; {EnumerateShell}TheEnumerateShell
procedure sets up a catalog information parameter block with a pointer to a string variable and the volume reference number passed to it. It then calls theEnumerateDir
procedure, which uses indexed calls toPBGetCatInfo
to read the catalog information about all items in the specified directory. If an item is a directory (as indicated by thekFolderBit
bit of theioFlAttrib
field of the parameter block),EnumerateDir
calls itself recursively to enumerate the contents of that directory. If an item is a file,EnumerateDir
performs whatever processing is appropriate.Note that
EnumerateDir
resets theioDrDirID
field before callingPBGetCatInfo
. This is necessary becausePBGetCatInfo
returns a file ID number in that field if the item is a file. TheEnumerateDir
procedure also clears theioACUser
field. You need to do this if your search depends on the value in that field after the call toPBGetCatInfo
, because the value returned in that field for local volumes is meaningless.To search an entire volume, call the
EnumerateShell
procedure with thevRefNum
parameter set to the volume reference number of the volume you want to search and thedirID
parameter set tofsRtDirID
. You can also do a partial search of a volume by specifying a different directory ID in thedirID
parameter.