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


Searching a Volume

To search a volume efficiently, you can use the PBCatSearch function. The PBCatSearch 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 ask PBCatSearch to match files or directories using many types of criteria, including

Like all low-level File Manager functions, PBCatSearch exchanges information with your application through a parameter block. The PBCatSearch function uses the csParam variant of the basic parameter block defined by the HParamBlockRec data type. That variant includes two fields, ioSearchInfo1 and ioSearchInfo2, that contain the addresses of two catalog information records (of type CInfoPBRec). 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 and ioSearchInfo2 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 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-11 Fields in ioSearchInfo1 and ioSearchInfo2 used for a file
FieldMeaning in ioSearchInfo1Meaning in ioSearchInfo2
ioNamePtrPointer to filenameReserved (must be NIL)
ioFlAttribDesired file attributesMask for file attributes
ioFlFndrInfoDesired Finder informationMask for Finder information
ioFlLgLenSmallest logical size of data forkLargest logical size
ioFlPyLenSmallest physical size of data forkLargest physical size
ioFlRLgLenSmallest logical size of resource forkLargest logical size
ioFlRPyLenSmallest physical size of resource forkLargest physical size
ioFlCrDatEarliest file creation dateLatest file creation date
ioFlMdDatEarliest file modification dateLatest file modification date
ioFlBkDatEarliest file backup dateLatest file backup date
ioFlXFndrInfoDesired extended Finder informationMask for Finder information
ioFlParIDSmallest directory ID of file's parentLargest parent directory ID

Table 2-12 Fields in ioSearchInfo1 and ioSearchInfo2 used for a directory
FieldMeaning in ioSearchInfo1Meaning in ioSearchInfo2
ioNamePtrPointer to directory nameReserved (must be NIL)
ioFlAttribDesired directory attributesMask for directory attributes
ioDrUsrWdsDesired Finder informationMask for Finder information
ioDrNmFlsSmallest number of files in directoryLargest number of files
ioDrCrDatEarliest directory creation dateLatest creation date
ioDrMdDatEarliest directory modification dateLatest modification date
ioDrBkDatEarliest directory backup dateLatest backup date
ioDrFndrInfoDesired extended Finder informationMask for Finder information
ioDrParIDSmallest directory ID of directory's parentLargest parent directory ID

The PBCatSearch function searches only on bits 0 and 4 in the file attributes
field (ioFlAttrib).
BitMeaning
0Set if the file or directory is locked.
4Set if the item is a directory.

Note
The PBCatSearch function cannot use the additional bits returned in the ioFlAttrib field by the PBGetCatInfo function.
To give 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 the ioSearchBits field in the PBCatSearch parameter block. To determine the value of ioSearchBits, add the appropriate constants. To match all files and directories on a volume (including the volume's root directory), set ioSearchBits 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, set ioSearchBits 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 the fsSBNegate bit. If that bit is set, PBCatSearch reverses the entry's match status (that is, if the entry is a match but the fsSBNegate 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).

Note
The fsSBNegate bit is ignored during searches of remote volumes that support AFP version 2.1.
Although using 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 the ioSearchTime field of the parameter block and keeping an index in the ioCatPosition field. The PBCatSearch function stores its directory-location index in a catalog position record, which is defined by the CatPositionRec 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 the initialize field to 0. When PBCatSearch exits because of a timeout, it updates the record so that it describes the next entry to be searched. When you call PBCatSearch 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 the ioMatchPtr field.

Note
The ioSearchTime field is not used by AFP volumes. To break up a potentially lengthy search into smaller searches on AFP volumes, use
the ioReqMatchCount field to specify the maximum number of matches to return.
Listing 2-3 illustrates how to use 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;
When PBCatSearch is not available in the current operating environment or is not supported by the volume you wish to search, you'll need to use PBGetCatInfo to perform a recursive, indexed search through the volume's directory hierarchy. This
kind of search is usually much slower than a search with PBCatSearch, and you
can encounter problems you avoid by using PBCatSearch. For example, a
recursive, indexed search can require a large amount of stack space. The procedure EnumerateShell 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}
The EnumerateShell 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 the EnumerateDir procedure, which uses indexed calls to PBGetCatInfo to read the catalog information about all items in the specified directory. If an item is a directory (as indicated by the kFolderBit bit of the ioFlAttrib 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 the ioDrDirID field before calling PBGetCatInfo. This is necessary because PBGetCatInfo returns a file ID number in that field if the item is a file. The EnumerateDir procedure also clears the ioACUser field. You need to do this if your search depends on the value in that field after the call to PBGetCatInfo, because the value returned in that field for local volumes is meaningless.

To search an entire volume, call the EnumerateShell procedure with the vRefNum parameter set to the volume reference number of the volume you want to search and the dirID parameter set to fsRtDirID. You can also do a partial search of a volume by specifying a different directory ID in the dirID parameter.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
2 JUL 1996