|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: File: CatSearch.c ! 27: ! 28: Contains: CatSearch (fast search of all files on a volume) ! 29: ! 30: Version: System 7.5.x (Tempo?) ! 31: ! 32: Copyright: � 1996-1997 by Apple Computer, Inc., all rights reserved. ! 33: ! 34: File Ownership: ! 35: ! 36: DRI: Mark Day ! 37: ! 38: Other Contact: Don Brady ! 39: ! 40: Technology: HFS+ ! 41: ! 42: Writers: ! 43: ! 44: (JL) Jim Luther ! 45: (RNP) Roger Pantos ! 46: (DSH) Deric Horn ! 47: (djb) Don Brady ! 48: (msd) Mark Day ! 49: ! 50: Change History (most recent first): ! 51: <Rhap> 03/31/98 djb Sync up with final HFSVolumes.h header file. ! 52: ! 53: 4/14/98 DSH Now also compile some compare routines for Rhapsody for use in searchfs(). ! 54: <CS18> 11/3/97 JL #2001483 - Return WDCBRecPtr from CatSearchC. ! 55: <CS17> 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. ! 56: <CS16> 10/17/97 msd Conditionalize DebugStrs. ! 57: <CS15> 10/10/97 msd Bug 1683670. InitCatSearch was calling the wrong routine to ! 58: flush the volume; only the user files were getting flushed. ! 59: Added casts to Ptr for first parameter to UprText. ! 60: <CS14> 9/27/97 RNP Replace UprString() with UprText(). ! 61: <CS13> 9/9/97 msd The PLstrcmp routine we link against has a bug with one ! 62: character strings, so just call our own PascalBinaryCompare ! 63: instead. ! 64: <CS12> 9/4/97 msd In CatalogNodeData, change attributeModDate to modifyDate. ! 65: <CS11> 7/28/97 msd Use fast new B-Tree scanner. ! 66: <CS10> 7/23/97 msd Radar #1668914. CatSearch should compare the file's backup date ! 67: with the search info's backup date range, not the create date ! 68: range. The mod date compare had the same problem. ! 69: <CS9> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name ! 70: collision ! 71: <CS8> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line ! 72: <CS7> 6/24/97 djb Include "CatalogInternal.h" ! 73: <CS6> 6/20/97 msd Use contentModDate and attributeModDate fields instead of ! 74: modifyDate. Use CatalogNodeData as common record format. Got rid ! 75: of NEW_CATSEARCH define by removing old code. ! 76: <CS5> 6/17/97 msd Bug #1661443. Initialize cat position to parent dirID = ! 77: fsRtParID. When restoring a cat position, special case that ! 78: parent ID since there is no such thread record. If ioSearchTime ! 79: is -1, assume they meant infinite, and use 0 instead. The call ! 80: to ConvertUnicodeToHFSName in CheckCriteria was getting ! 81: parameters from the wrong places. ! 82: <4> 6/13/97 djb Change PrepareOutputName calls to ConvertUnicodeToHFSName calls. ! 83: <CS3> 6/9/97 msd Convert HFS Plus dates from UTC to local time in MakeCatDirRec ! 84: and MakeCatFilRec. ! 85: <CS2> 5/16/97 msd Fix some string type conversion problems in InsertMatch(). ! 86: <CS1> 4/24/97 djb first checked in ! 87: <HFS22> 4/16/97 djb Always use new B-tree code. ! 88: <HFS21> 4/11/97 DSH use extended VCB fields catalogRefNum, and extentsRefNum. ! 89: <HFS20> 3/27/97 djb Unicode string lengths are now passed as a byte count. ! 90: <HFS19> 2/19/97 djb Get in sync with new B-tree definitions... ! 91: <HFS18> 2/6/97 msd When instrumentation is active, log a complete FSSpec when a ! 92: match is inserted into the buffer. ! 93: <HFS17> 2/5/97 msd On HFS+ disks, CheckCriteria needs to test against the HFS-style ! 94: copy of the catalog record rather than the HFS variants of the ! 95: CatalogRecord of the actual catalog data. ! 96: <HFS16> 1/29/97 msd InitCatSearch needs to preset the BTree position by searching ! 97: for a node before the directory record of the root so that the ! 98: root will be searched, too. ! 99: <HFS15> 1/29/97 msd CheckCriteria was ignoring the fsSBNegate bit when testing the ! 100: ioDirMask bit in the file attributes. Made sure that thread ! 101: records never match. ! 102: <HFS14> 1/17/97 msd Add trivial instrumentation. ! 103: <HFS13> 1/16/97 msd When using the new BTree manager, the old btcWCount field is ! 104: always zero, so use numUpdateNodes instead. However, ! 105: numUpdateNodes can be zero so use numUpdateNodes+1 instead; this ! 106: still allows the caller to set the writeCount in the ! 107: CatPositionRec to zero to indicate a new search. ! 108: <HFS12> 1/9/97 djb Get in sync with new HFSVolumesPriv.i.. ! 109: <HFS11> 1/9/97 msd The CatPosition was not being updated during or after the call. ! 110: Also, InitCatSearch was going back to the root directory instead ! 111: of the parent directory specified in the CatPosition. ! 112: InitCatSearch should not use GetCatalogNode; it should use ! 113: SearchBTreeRecord instead since we want to be able to find ! 114: thread records and move relative to them. ! 115: <HFS10> 1/3/97 djb Integrated latest HFSVolumesPriv.h changes. ! 116: <HFS9> 12/23/96 msd Oops. Re-enable timers. ! 117: <HFS8> 12/23/96 msd Update to use new BTree interfaces. Conditionalized the code via ! 118: the NEW_CATSEARCH symbol. The code should compile both ways, but ! 119: should be cleaned up later. There is a DebugStr in case the ! 120: BTree returns an unexpected error. Performance is noticably ! 121: worse than the prior implementation. ! 122: <HFS7> 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB ! 123: <HFS6> 12/18/96 msd Use PrepareOutputName when copying a found item's name into ! 124: FSSpec array. ! 125: <HFS5> 12/12/96 msd Use the Unicode wrapper functions. ! 126: <HFS4> 12/10/96 msd First version of HFS+ changes complete. The HFS+ catalog data is ! 127: converted to a CatalogRecord before comparison. Copied code from ! 128: Catalog.c for dealing with the Unicode names. ! 129: <HFS3> 12/10/96 msd Begin HFS+ changes. Check PRAGMA_LOAD_SUPPORTED before loading ! 130: precompiled headers. ! 131: <HFS2> 12/10/96 msd Add support for precompiled headers. ! 132: <HFS1> 12/9/96 msd first checked in ! 133: ! 134: */ ! 135: ! 136: /* ! 137: Public routines: ! 138: CatSearchC ! 139: Searches the entire volume for files/folders matching given ! 140: criteria. It does this by reading every record in the Catalog ! 141: BTree; all non-index records are compared to the given criteria. ! 142: And files/folders that match have their FSSpec's returned ! 143: in a caller-supplied buffer. The caller may also provide a ! 144: buffer to use when reading the BTree; otherwise, a default ! 145: buffer within the File Manager is used. ! 146: ! 147: VerifyCatSearchPB ! 148: Validates the parameters in a CatSearch parameter block to ! 149: make sure the values are mutually consistent and in range. ! 150: ! 151: Internal routines: ! 152: ExtOffLineCheck ! 153: Make sure the given volume is both online and HFS (or HFS+). ! 154: If not, an appropriate error is returned. ! 155: ! 156: StartScan Initialize state for scan and return first record. ! 157: EndScan Cleanup state and return hint ! 158: ScanNextRecord Get the next record in the scan. ! 159: */ ! 160: ! 161: #if ( PRAGMA_LOAD_SUPPORTED ) ! 162: #pragma load PrecompiledHeaders ! 163: #else ! 164: #if TARGET_OS_MAC ! 165: #include <Timer.h> ! 166: #include <TextUtils.h> ! 167: #include <LowMemPriv.h> ! 168: #include <PLStringFuncs.h> ! 169: #else ! 170: #include "../headers/system/MacOSStubs.h" ! 171: #endif /* TARGET_OS_MAC */ ! 172: #endif /* PRAGMA_LOAD_SUPPORTED */ ! 173: ! 174: ! 175: ! 176: #include "../headers/HFSBtreesPriv.h" ! 177: #include "../headers/HFSVolumes.h" ! 178: #include "../headers/FileMgrInternal.h" ! 179: #include "../headers/system/HFSUnicodeWrappers.h" ! 180: #include "../headers/BTreesInternal.h" ! 181: #include "../headers/BTreesPrivate.h" ! 182: #include "../headers/BTreeScanner.h" ! 183: #include "../headers/CatalogPrivate.h" ! 184: ! 185: #if HFSInstrumentation ! 186: #include "../headers/system/Instrumentation.h" ! 187: #endif ! 188: ! 189: ! 190: #ifndef CATSEARCH_DEBUG ! 191: #define CATSEARCH_DEBUG 1 ! 192: #endif ! 193: ! 194: #define BTREE_CB_TYPE BTreeControlBlock ! 195: #define BTREE_WRITE_COUNT(btcb) (btcb->numUpdateNodes+1) ! 196: ! 197: extern OSErr VerifyCatSearchPB( const CSParam *pb, UInt8 *outAttributes, UInt8 *outFlags ); ! 198: extern OSErr CatSearchC( CSParam *pb, WDCBRecPtr *wdcb ); ! 199: extern OSErr ExtOffLineCheck( ExtendedVCB *vcb ); ! 200: ! 201: extern OSErr CheckExternalFileSystem( ExtendedVCB *vcb ); ! 202: extern OSErr DeturmineVolume3( VolumeParam *iopb, short *nameLength, Boolean *nameSpecified, ExtendedVCB **vcb, WDCBRec **wdcb, unsigned char **pathName ); ! 203: extern OSErr FlushVolume( ExtendedVCB *vcb ); ! 204: extern OSErr FlushVolumeBuffers( ExtendedVCB *vcb ); ! 205: extern OSErr ChkNode_glue( BTNodeDescriptor *node, BTREE_CB_TYPE *btcb ); ! 206: extern void LocRec_glue( BTNodeDescriptor *node, BTREE_CB_TYPE *btcb, UInt32 recordNumber, ! 207: Ptr *key, Ptr *data, UInt32 *recordSize ); ! 208: ! 209: // ! 210: //�� These need to be moved to an interface file ! 211: // ! 212: enum { ! 213: kBTreePrevious = -1, ! 214: kBTreeCurrent = 0, ! 215: kBTreeNext = 1 ! 216: ! 217: }; ! 218: ! 219: enum { ! 220: // ! 221: // Masks for bits in the file attributes ! 222: // ! 223: // kFileLockedMask = 1, ! 224: kMaskBatAttributes = ~(ioDirMask | kHFSFileLockedMask), ! 225: ! 226: // ! 227: // Masks for search bits ! 228: // ! 229: kMaskNotSearchInfo2 = ~(fsSBPartialName | fsSBFullName | fsSBNegate), ! 230: kMaskLengthBits = (fsSBFlLgLen | fsSBFlPyLen | fsSBFlRLgLen | fsSBFlRPyLen), ! 231: ! 232: // ! 233: // Masks for flags ! 234: // ! 235: kIncludeDirs = 1, ! 236: kIncludeFiles = 2, ! 237: kIncludeNames = 4, ! 238: ! 239: kMinimumBufferSize = 512 ! 240: }; ! 241: ! 242: ! 243: struct CatPosition { ! 244: UInt32 writeCount; // The BTree's write count (to see if the catalogwriteCount ! 245: // changed since the last search). If 0, the rest ! 246: // of the record is invalid, start from beginning. ! 247: UInt32 nextNode; // node number to resume search ! 248: UInt32 nextRecord; // record number to resume search ! 249: UInt32 recordsFound; // number of leaf records seen so far ! 250: }; ! 251: typedef struct CatPosition CatPosition; ! 252: ! 253: ! 254: typedef BTScanState ScanState; ! 255: ! 256: ! 257: struct CatSearchState { ! 258: TMTask timer; // MUST be first field! ! 259: CSParam *pb; ! 260: Str31 targetName; // Upper case version of name being matched against ! 261: FSSpec *nextMatch; ! 262: long searchBits; ! 263: CatalogKey *currentKey; // Pointer to key within current record ! 264: CatalogRecord *currentData; // Pointer to data within current record ! 265: #if HFSInstrumentation ! 266: InstTraceClassRef trace; ! 267: InstEventTag eventTag; ! 268: InstDataDescriptorRef traceDescriptor; ! 269: #endif ! 270: short vRefNum; // Volume reference of volume being searched ! 271: Boolean isHFS; // True if volume is HFS ! 272: UInt8 attributes; // desired file attributes to match against ! 273: UInt8 flags; ! 274: Boolean timerCompleted; // Set to true by timer's completion routine ! 275: }; ! 276: typedef struct CatSearchState CatSearchState; ! 277: ! 278: #if TARGET_OS_MAC ! 279: static OSErr InitCatSearch( ExtendedVCB *volume, CSParam *pb, ScanState *scanState ); ! 280: static void UpdateCatPosition( const ExtendedVCB *volume, CatPosition *endingPosition, const ScanState *scanState ); ! 281: static void InsertMatch(CatSearchState *searchState); ! 282: static Boolean CheckCriteria(ExtendedVCB *vcb, const CatSearchState *searchState); ! 283: Boolean CompareMasked(const UInt32 *thisValue, const UInt32 *compareData, ! 284: const UInt32 *compareMask, UInt32 count); ! 285: Boolean ComparePartialName(ConstStr31Param thisName, ConstStr31Param substring); ! 286: Boolean CompareFullName(ConstStr31Param thisName, ConstStr31Param testName); ! 287: #endif /* TARGET_OS_MAC */ ! 288: Boolean CompareRange(UInt32 val, UInt32 low, UInt32 high); ! 289: #define CompareRange(val, low, high) (val >= low && val <= high) ! 290: ! 291: extern void CSTimerGlue(void); ! 292: extern void CatSearchTimerComplete(CatSearchState *state); ! 293: ! 294: UInt32 Low32BitsPinned(UInt64 x); ! 295: #define Low32BitsPinned(x) (x.hi ? 0xFFFFFFFF : x.lo) ! 296: ! 297: ! 298: ! 299: /* ! 300: ;__________________________________________________________________________________ ! 301: ; ! 302: ; Routine: CMCatSearch ! 303: ; ! 304: ; Function: Locates files by search criteria ! 305: ; ! 306: ; Input: A0.L - parameter block pointer ! 307: ; ! 308: ; Register Usage (during call): ! 309: ; A0.L - scratch D0.L - scratch ! 310: ; A1.L - scratch D1.L - scratch ! 311: ; A2.L - scratch D2.L - scratch ! 312: ; A3.L - pointer to CatSearch State Record (CSSR) D3.L - scratch ! 313: ; A4.L - pointer to PScan State Record (PSR) D4.L - scratch ! 314: ; A5.L - pointer to user's param block D5.L - ioSearchBits ! 315: ; sp - standard file system stack ! 316: ; D7.L - ioActMatchCount ! 317: ; ! 318: ; Output: D0.W - result code (noErr, extFSErr, ioErr, nsvErr, catChanged, paramErr) ! 319: ; A0.L, A1.L - trash ! 320: ; D0.L, D1.L, D2.L - trash ! 321: ;__________________________________________________________________________________ ! 322: */ ! 323: #if TARGET_OS_MAC ! 324: OSErr CatSearchC( CSParam *pb, WDCBRecPtr *wdcb ) ! 325: { ! 326: OSErr err; ! 327: ExtendedVCB *vcb; ! 328: short volNameLength; ! 329: Boolean volNameSpecified; ! 330: unsigned char *pathname; ! 331: UInt32 catalogRecordSize; ! 332: ScanState scanState; ! 333: CatSearchState searchState; ! 334: Boolean timerInstalled = false; ! 335: #if HFSInstrumentation ! 336: FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars(); ! 337: #endif ! 338: ! 339: ! 340: #if HFSInstrumentation ! 341: searchState.trace = (InstTraceClassRef) fsVars->later[0]; ! 342: searchState.traceDescriptor = (InstDataDescriptorRef) fsVars->later[1]; ! 343: searchState.eventTag = InstCreateEventTag(); ! 344: InstLogTraceEvent( searchState.trace, searchState.eventTag, kInstStartEvent); ! 345: #endif ! 346: ! 347: // ! 348: // Start a timer for the call ! 349: // ! 350: searchState.timerCompleted = false; ! 351: ! 352: if (pb->ioSearchTime != 0 && pb->ioSearchTime != -1) { ! 353: searchState.timer.tmAddr = (TimerUPP) CSTimerGlue; ! 354: InsTime((QElem *) &searchState.timer); ! 355: PrimeTime((QElem *) &searchState.timer, pb->ioSearchTime); ! 356: timerInstalled = true; ! 357: } ! 358: ! 359: // ! 360: // Find the volume specified ! 361: // ! 362: err = DeturmineVolume3((VolumeParam *) pb, &volNameLength, &volNameSpecified, &vcb, wdcb, &pathname); ! 363: if (err != noErr) goto ErrorExit; ! 364: ! 365: // ! 366: // Make sure the volume is ours, and online. ! 367: // ! 368: err = ExtOffLineCheck(vcb); ! 369: if (err != noErr) goto ErrorExit; ! 370: ! 371: // ! 372: // Set up some information about the volume ! 373: // ! 374: searchState.vRefNum = vcb->vcbVRefNum; ! 375: if (vcb->vcbSigWord == kHFSSigWord) ! 376: searchState.isHFS = true; ! 377: else ! 378: searchState.isHFS = false; ! 379: ! 380: // ! 381: // Clear ioActMatchCount ! 382: // ! 383: pb->ioActMatchCount = 0; ! 384: ! 385: // ! 386: // Verify the parameter block ! 387: // ! 388: err = VerifyCatSearchPB(pb, &searchState.attributes, &searchState.flags); ! 389: if (err != noErr) goto ErrorExit; ! 390: ! 391: // ! 392: // If no matches requested, exit early ! 393: // ! 394: if (pb->ioReqMatchCount == 0) { ! 395: err = noErr; ! 396: goto ErrorExit; ! 397: } ! 398: ! 399: searchState.pb = pb; ! 400: searchState.searchBits = pb->ioSearchBits; ! 401: searchState.nextMatch = pb->ioMatchPtr; ! 402: ! 403: // ! 404: // If a name is part of the criteria, prepare it for matching. (We make it upper ! 405: // case and remove diacriticals.) ! 406: // ! 407: if (searchState.flags & kIncludeNames) { ! 408: StringPtr name; ! 409: name = pb->ioSearchInfo1->hFileInfo.ioNamePtr; ! 410: // If caller's name is longer than HFS names can be, then ! 411: // we can optimize. ! 412: if (name[0] > 31) { ! 413: // Nothing can possibly match the given name. If the caller asked ! 414: // us to negate the search, then we need to return everything. ! 415: if (searchState.searchBits & fsSBNegate) { ! 416: searchState.searchBits = 0; // causes everything to match ! 417: } ! 418: else { ! 419: err = eofErr; // nothing left to match ! 420: goto ErrorExit; ! 421: } ! 422: } ! 423: else { ! 424: // ! 425: // Make a copy of the supplied name and convert it to upper case ! 426: // for later comparison. ! 427: // ! 428: //�� There is a bug in the assembly CatSearch: it calls _FSUprString which ! 429: //�� is really just _UpperString. It passes the length of the string in D0. ! 430: //�� According to the interfaces, the second parameter (in D0) is a boolean ! 431: //�� to determine whether it should be diacritical sensitive (i.e. whether it ! 432: //���should leave diacriticals vs. stripping them). Apparently, this always ! 433: //�� evaluates to false (testing the high bit of the word?). ! 434: // ! 435: //�� I disagree with the above analysis. The $A054 trap, which _FSUprString is ! 436: //�� aliased to, is actually UprStringTrap(), implemented in :SuperMario:OS:SysUtil.a. ! 437: //�� It does in fact take a ptr to text in A0 and len in D0. UpperString(), ! 438: //���on the other hand, is glue in OSTrapsGlue.a which munges ! 439: //�� the input parameters (including the diac boolean) and then turns around and calls ! 440: //�� _UprString, with A0 pointing to text and D0 holding length. Same as assembly CatSearch. ! 441: //�� So _UprString (or _UpperString) != UpperString(), sadly enough. ! 442: //�� - RNP. ! 443: // ! 444: // Note: we still do this even for HFS+, since we want to compare the names that ! 445: // would actually be returned in the same way as HFS. That is name comparisons ! 446: // for HFS and HFS+ should behave identically if they returned the same name via ! 447: // GetCatInfo, even though HFS+ may be truncating or otherwise mangling the name ! 448: // to fit in 31 characters; we want to compare against the mangled name. ! 449: // ! 450: BlockMoveData(name, searchState.targetName, sizeof(Str31)); ! 451: UprText( (Ptr)(searchState.targetName + 1), searchState.targetName[ 0]); ! 452: } ! 453: } ! 454: ! 455: // ! 456: // Set up for the search. ! 457: // ! 458: err = InitCatSearch(vcb, pb, &scanState); ! 459: #if DEBUG_BUILD ! 460: if (err > 0) DebugStr("\pCatSearch: Internal Error"); ! 461: #endif ! 462: ! 463: // ! 464: // Now loop over the records ! 465: // ! 466: while (err == noErr) { ! 467: err = BTScanNextRecord(&scanState, searchState.timerCompleted, (void**)&searchState.currentKey, (void**)&searchState.currentData, &catalogRecordSize); ! 468: if (err == noErr) { ! 469: // Check for a match ! 470: if (CheckCriteria(vcb, &searchState)) { // Found a match? ! 471: err = BTScanCacheNode(&scanState); // Make sure current node is cached ! 472: InsertMatch(&searchState); // Return in to caller ! 473: if (++pb->ioActMatchCount == pb->ioReqMatchCount) // Got enough matches yet? ! 474: break; ! 475: } ! 476: } ! 477: } ! 478: ! 479: // ! 480: // See if we've scanned the entire Catalog BTree. If so, return eofErr. ! 481: // If we exited because of a timeout, then it's not an error. ! 482: // ! 483: if (err == btNotFound || err == fsBTEndOfIterationErr) ! 484: err = eofErr; ! 485: if (err == fsBTTimeOutErr) ! 486: err = noErr; ! 487: #if DEBUG_BUILD ! 488: if (err > 0) DebugStr("\pCatSearch: Internal Error"); ! 489: #endif ! 490: // ! 491: // Update caller's CatPosition so they can resume the search ! 492: // ! 493: UpdateCatPosition(vcb, (CatPosition *) &pb->ioCatPosition, &scanState); ! 494: ! 495: // ! 496: // If we get here, we never actually started a scan, so all we have left ! 497: // is to remove the timer (if we installed one) and return the error code. ! 498: // ! 499: ErrorExit: ! 500: // ! 501: // Stop timer ! 502: // ! 503: if (timerInstalled) ! 504: RmvTime((QElem *) &searchState.timer); ! 505: ! 506: #if HFSInstrumentation ! 507: InstLogTraceEvent( searchState.trace, searchState.eventTag, kInstEndEvent); ! 508: #endif ! 509: ! 510: return err; ! 511: } ! 512: ! 513: #endif ! 514: ! 515: /* ! 516: ;__________________________________________________________________________________ ! 517: ; ! 518: ; Routine: VerifyCSPB ! 519: ; ! 520: ; Function: Verify that a param block contains legal values ! 521: ; ! 522: ; Input: A0.L - parameter block pointer ! 523: ; ! 524: ; Register Usage (during call): ! 525: ; A0.L - pointer to user's param block D0.L - scratch ! 526: ; A1.L - pointer to ioSearchInfo1 D1.L - scratch ! 527: ; D2.B - copy of user's ioFlAttrib mask ! 528: ; D3.L - cssr.flags byte ! 529: ; A4.L - pointer to ioSearchInfo2 ! 530: ; A5.L - pointer to user's param block D5.L - ioSearchBits ! 531: ; ! 532: ; Output: ! 533: ; d0.W - result code (noErr, paramErr) ! 534: ; d2.b - copy of user's ioFlAttrib mask, ioDirFlg masked ! 535: ; d3.b - cssr.flags with inclFiles, inclDirs and inclNames set correctly ! 536: ; ! 537: ; Here are the parameter checking rules for PBCatSearch: <1.3> ! 538: ; The labels at the left also appear in the code which checks that rule. ! 539: ; ! 540: ; You get a paramErr if ! 541: ; P1 ioMBufPtr is nil ! 542: ; P2 ioSearchInfo1 is nil ! 543: ; P3 (ioSearchBits includes not(fsSBPartialName or fsSBFullName or fsSBNegate)) and ioSearchInfo2 is nil; ! 544: ; i.e. A selected search bit requires the presence of ioSearchInfo2 ! 545: ; ! 546: ; Then these, ! 547: ; ioSearchBits rules: You get a paramErr if ! 548: ; P4 fsSBPartialName ! 549: ; and (ioSearchInfo1->ioNamePtr = (nil or empty string)) ! 550: ; P5 fsSBFullName (same as above) ! 551: ; P6 fsSBFlAttrib and some bit other than 0 (locked) or 4 (directory) returns paramErr ! 552: ; P7 search includes directories and ! 553: ; (ioSearchBits includes fsSBFlAttrib) and (ioSearchInfo2^.ioFlAttrib bit 0 = 1) ! 554: ; return paramErr ! 555: ; (i.e. "locked directory" makes no sense) ! 556: ; P8 fsSBDrNmFls and files returns paramErr ! 557: ; P9 fsSBFlLgLen and directories returns paramErr ! 558: ; P10 fsSBFlPyLen (same as above) ! 559: ; P11 fsSBFlRLgLen (same as above) ! 560: ; P12 fsSBFlRPyLen (same as above) ! 561: ; ! 562: ; A search includes (files only) if ! 563: ; ioSearchBits includes fsSBFlAttrib ! 564: ; - and - ! 565: ; ioSearchInfo1^.ioFlAttrib bit 4 = 0 i.e. explicitly looking for non-directories ! 566: ; - and - ! 567: ; ioSearchInfo2^.ioFlAttrib bit 4 = 1 ! 568: ; ! 569: ; A search includes (directories only) if ! 570: ; ioSearchBits includes fsSBFlAttrib ! 571: ; - and - ! 572: ; ioSearchInfo1^.ioFlAttrib bit 4 = 1 i.e. explicitly looking for directories ! 573: ; - and - ! 574: ; ioSearchInfo2^.ioFlAttrib bit 4 = 1 ! 575: ; ! 576: ; A search includes both if ! 577: ; ioSearchBits includes fsSBFlAttrib ! 578: ; - and - ! 579: ; ioSearchInfo2^.ioFlAttrib bit 4 = 0 i.e. don't care about the directory bit ! 580: ; ! 581: ; - OR - ! 582: ; ioSearchBits doesn't include fsSBFlAttrib i.e. don't care about attributes at all ! 583: ;__________________________________________________________________________________ ! 584: */ ! 585: ! 586: OSErr VerifyCatSearchPB( ! 587: const CSParam *pb, // user's parameter block ! 588: UInt8 *outAttributes, // ioFlAttrib, with ioDirFlg cleared ! 589: UInt8 *outFlags) // cssr.flags with inclFiles, inclDirs and inclNames set correctly ! 590: { ! 591: SInt8 attributes = 0; // local copy of output outAttributes ! 592: UInt8 flags; // local copy of output outFlags ! 593: long searchBits; // copy of pb->ioSearchBits ! 594: CInfoPBPtr searchInfo1; // copy of pb->ioSearchInfo1 ! 595: CInfoPBPtr searchInfo2; // copy of pb->ioSearchInfo2 ! 596: ! 597: // ! 598: // P1: User must supply a buffer to return the found FSSpec's ! 599: // ! 600: if (pb->ioMatchPtr == NULL) ! 601: goto ParamErrExit; ! 602: ! 603: // ! 604: // P2: Must supply values to compare against (ioSearchInfo1) ! 605: // ! 606: searchInfo1 = pb->ioSearchInfo1; ! 607: searchInfo2 = pb->ioSearchInfo2; ! 608: if (searchInfo1 == NULL) ! 609: goto ParamErrExit; ! 610: ! 611: searchBits = pb->ioSearchBits; ! 612: ! 613: // ! 614: // P3: See if we need any end-of-range or mask values (in ioSearchInfo2). ! 615: // If so, the pointer must be non-NULL. ! 616: // ! 617: if (((searchBits & kMaskNotSearchInfo2) != 0) && (searchInfo2 == NULL)) ! 618: goto ParamErrExit; ! 619: ! 620: flags = 0; ! 621: ! 622: // ! 623: // P4-5: If we're searching by name (partial or full), then check the name passed. ! 624: // ! 625: if (searchBits & (fsSBPartialName | fsSBFullName)) { ! 626: StringPtr name = searchInfo1->hFileInfo.ioNamePtr; ! 627: if (name == NULL || name[0] == 0) ! 628: goto ParamErrExit; ! 629: flags |= kIncludeNames; ! 630: } ! 631: ! 632: // ! 633: // Determine whether we're looking for files, folders, or both. ! 634: // ! 635: if (searchBits & fsSBFlAttrib) { ! 636: attributes = searchInfo2->hFileInfo.ioFlAttrib; // get mask for attributes ! 637: if (attributes & kMaskBatAttributes) // P6: only locked and directory bits are allowed ! 638: goto ParamErrExit; ! 639: if (attributes & ioDirMask) // do they care whether object is a file or folder? ! 640: if (searchInfo1->hFileInfo.ioFlAttrib & ioDirMask) ! 641: flags |= kIncludeDirs; // wanted folders only ! 642: else ! 643: flags |= kIncludeFiles; // wanted files only ! 644: else ! 645: flags |= (kIncludeDirs | kIncludeFiles); // caller didn't care about files vs. folders ! 646: } ! 647: else ! 648: flags |= (kIncludeDirs | kIncludeFiles); ! 649: ! 650: attributes &= ~ioDirMask; // clear ioDirMask since it isn't actually on disk ! 651: ! 652: // ! 653: // P7: If they cared about file attributes, and search includes folders, then ! 654: // ioLockFlag must not be set (since it is meaningless for folders). ! 655: // ! 656: if ((flags & kIncludeDirs) && (searchBits & fsSBFlAttrib) && (attributes & kHFSFileLockedMask)) ! 657: goto ParamErrExit; ! 658: ! 659: // ! 660: // P8: If search includes files, then # of files per folder must not be set. ! 661: // ! 662: if ((searchBits & fsSBDrNmFls) && (flags & kIncludeFiles)) ! 663: goto ParamErrExit; ! 664: ! 665: // ! 666: // P9-P12: If search includes directories, then none of the fork length bits ! 667: // must be set. ! 668: // ! 669: if ((flags & kIncludeDirs) && (searchBits & kMaskLengthBits)) ! 670: goto ParamErrExit; ! 671: ! 672: // ! 673: // When we get here, all the checks have passed. Return the output flags ! 674: // and file attributes. ! 675: // ! 676: *outAttributes = attributes; ! 677: *outFlags = flags; ! 678: return noErr; ! 679: ! 680: // ! 681: // If we get here, there was a problem with one of the parameters. ! 682: // ! 683: ParamErrExit: ! 684: return paramErr; ! 685: } ! 686: ! 687: ! 688: ! 689: // ! 690: // Copy the FSSpec for the current catalog node into the caller's match buffer ! 691: // ! 692: #if TARGET_OS_MAC ! 693: static void InsertMatch(CatSearchState *searchState) ! 694: { ! 695: CatalogKey *current; ! 696: FSSpec *match; ! 697: ! 698: // Get the key for the item we just found, and the place where we should ! 699: // store the item's FSSpec ! 700: current = searchState->currentKey; ! 701: match = searchState->nextMatch; ! 702: ! 703: // Copy vRefNum ! 704: match->vRefNum = searchState->vRefNum; ! 705: ! 706: if (searchState->isHFS) { ! 707: // Copy parentDirID ! 708: match->parID = current->hfs.parentID; ! 709: ! 710: // Copy the name as a PString ! 711: BlockMoveData(current->hfs.nodeName, &match->name[0], StrLength(current->hfs.nodeName) + 1); ! 712: } ! 713: else { ! 714: TextEncoding encoding; ! 715: HFSCatalogNodeID cnid; ! 716: ! 717: cnid = searchState->currentData->hfsPlusFile.fileID; // note: cnid at same offset for folders ! 718: encoding = searchState->currentData->hfsPlusFile.textEncoding; // note: textEncoding at same offset for folders ! 719: ! 720: // Copy parentDirID ! 721: match->parID = current->hfsPlus.parentID; ! 722: ! 723: // Copy the name as a PString ! 724: (void) ConvertUnicodeToHFSName( ¤t->hfsPlus.nodeName, encoding, cnid, &match->name[0]); ! 725: } ! 726: ! 727: #if HFSInstrumentation ! 728: // InstLogTraceEvent( searchState->trace, searchState->eventTag, kInstMiddleEvent); ! 729: { ! 730: struct { ! 731: long vRefNum; ! 732: long parID; ! 733: char name[32]; ! 734: } x; ! 735: unsigned len; ! 736: ! 737: x.vRefNum = match->vRefNum; ! 738: x.parID = match->parID; ! 739: ! 740: len = match->name[0]; ! 741: BlockMoveData(&match->name[1], &x.name[0], len); ! 742: x.name[len] = 0; ! 743: ! 744: InstLogTraceEventWithDataStructure( searchState->trace, searchState->eventTag, kInstMiddleEvent, ! 745: searchState->traceDescriptor, (UInt8 *) &x, sizeof(x)); ! 746: } ! 747: #endif ! 748: ! 749: // Point to next FSSpec in caller's buffer ! 750: searchState->nextMatch++; ! 751: } ! 752: #endif /* TARGET_OS_MAC */ ! 753: ! 754: ! 755: ! 756: // ! 757: // Determine whether the current catalog node matches the caller's criteria. Return ! 758: // true if the object matches. ! 759: // ! 760: #if TARGET_OS_MAC ! 761: static Boolean CheckCriteria(ExtendedVCB *vcb, const CatSearchState *searchState) ! 762: { ! 763: CatalogKey *key; ! 764: Boolean matched; ! 765: long searchBits; ! 766: CInfoPBRec *searchInfo1; ! 767: CInfoPBRec *searchInfo2; ! 768: CatalogNodeData catData; ! 769: ! 770: key = searchState->currentKey; ! 771: ! 772: // Change the catalog record data into a single common form ! 773: catData.nodeType = 0; // mark this record as not in use ! 774: CopyCatalogNodeData(vcb, searchState->currentData, &catData); ! 775: ! 776: switch (searchState->currentData->recordType) { ! 777: case kHFSFolderThreadRecord: ! 778: return false; // Never match a thread record! ! 779: break; ! 780: case kHFSPlusFolderThreadRecord: ! 781: return false; // Never match a thread record! ! 782: break; ! 783: ! 784: case kHFSFolderRecord: ! 785: case kHFSFileRecord: ! 786: case kHFSPlusFolderRecord: ! 787: case kHFSPlusFileRecord: ! 788: break; ! 789: ! 790: default: ! 791: return false; // Not a file or folder record, so can't search it ! 792: } ! 793: ! 794: searchBits = searchState->searchBits; ! 795: matched = true; // Assume we got a match ! 796: ! 797: // See if this type of object (file vs. folder) is one of the types they're trying ! 798: // to match. ! 799: if (catData.nodeType == kCatalogFolderNode && (searchState->flags & kIncludeDirs) == 0 ) { ! 800: // Found a folder, but they don't want folders. ! 801: matched = false; ! 802: goto TestDone; ! 803: } ! 804: if (catData.nodeType == kCatalogFileNode && (searchState->flags & kIncludeFiles) == 0 ) { ! 805: // Found a file, but they don't want files. ! 806: matched = false; ! 807: goto TestDone; ! 808: } ! 809: ! 810: searchInfo1 = searchState->pb->ioSearchInfo1; ! 811: searchInfo2 = searchState->pb->ioSearchInfo2; ! 812: ! 813: // ! 814: // First, attempt to match the name -- either partial or complete. ! 815: // If the volume is HFS+, then we need to make a Str31 version of the name ! 816: // to use for comparison. ! 817: // ! 818: if (searchBits & (fsSBPartialName | fsSBFullName)) { ! 819: Str31 keyName; ! 820: ConstStr31Param namePtr; ! 821: ! 822: // Make a pointer to a PString version of the name ! 823: if (searchState->isHFS) ! 824: namePtr = &key->hfs.nodeName[0]; ! 825: else { ! 826: TextEncoding encoding; ! 827: ! 828: encoding = searchState->currentData->hfsPlusFile.textEncoding; // same offset for folders ! 829: ! 830: (void) ConvertUnicodeToHFSName(&key->hfsPlus.nodeName, encoding, catData.nodeID, keyName); ! 831: namePtr = keyName; ! 832: } ! 833: ! 834: // Check for a partial name match ! 835: if (searchBits & fsSBPartialName) { ! 836: matched = ComparePartialName(namePtr, searchState->targetName); ! 837: // Exit if no match, or we no there's nothing more to compare ! 838: if (matched == false || searchBits == fsSBPartialName) ! 839: goto TestDone; ! 840: } ! 841: ! 842: // Check for a full name match ! 843: if (searchBits & fsSBFullName) { ! 844: matched = CompareFullName(namePtr, searchState->targetName); ! 845: // Exit if no match, or we no there's nothing more to compare ! 846: if (matched == false || searchBits == fsSBFullName) ! 847: goto TestDone; ! 848: } ! 849: } ! 850: ! 851: // ! 852: // parent ID ! 853: // ! 854: if (searchBits & fsSBFlParID) { ! 855: HFSCatalogNodeID parentID; ! 856: ! 857: // Note: ioFlParID and ioDrParID have the same offset in search info, so no ! 858: // need to test the object type here. However, we do need to test for HFS ! 859: // vs. HFSPlus, since their key structures are different. ! 860: ! 861: if (searchState->isHFS) ! 862: parentID = key->hfs.parentID; ! 863: else ! 864: parentID = key->hfsPlus.parentID; ! 865: ! 866: matched = CompareRange(parentID, searchInfo1->hFileInfo.ioFlParID, ! 867: searchInfo2->hFileInfo.ioFlParID); ! 868: if (matched == false) goto TestDone; ! 869: } ! 870: ! 871: // ! 872: // File attributes ! 873: // ! 874: if (searchBits & fsSBFlAttrib) { ! 875: UInt32 temp; ! 876: ! 877: temp = (catData.nodeFlags ^ searchInfo1->hFileInfo.ioFlAttrib) & searchState->attributes; ! 878: if (temp != 0) { ! 879: matched = false; ! 880: goto TestDone; ! 881: } ! 882: } ! 883: ! 884: // ! 885: // Number of files in a directory ! 886: // ! 887: if (searchBits & fsSBDrNmFls) { ! 888: matched = CompareRange(catData.valence, searchInfo1->dirInfo.ioDrNmFls, ! 889: searchInfo2->dirInfo.ioDrNmFls); ! 890: if (matched == false) goto TestDone; ! 891: } ! 892: ! 893: // ! 894: // Finder Info ! 895: // ! 896: if (searchBits & fsSBFlFndrInfo) { ! 897: UInt32 *thisValue; ! 898: ! 899: thisValue = (UInt32 *) &catData.finderInfo[0]; ! 900: ! 901: // Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so ! 902: // no need to test the object type here. ! 903: matched = CompareMasked(thisValue, (UInt32 *) &searchInfo1->hFileInfo.ioFlFndrInfo, ! 904: (UInt32 *) &searchInfo2->hFileInfo.ioFlFndrInfo, ! 905: sizeof(FInfo)/sizeof(UInt32)); ! 906: ! 907: if (matched == false) goto TestDone; ! 908: } ! 909: ! 910: // ! 911: // Extended Finder Info ! 912: // ! 913: if (searchBits & fsSBFlXFndrInfo) { ! 914: UInt32 *thisValue; ! 915: ! 916: thisValue = (UInt32 *) &catData.extFinderInfo[0]; ! 917: ! 918: // Note: ioFlXFndrInfo and ioDrFndrInfo have the same offset in search info, so ! 919: // no need to test the object type here. ! 920: matched = CompareMasked(thisValue, (UInt32 *) &searchInfo1->hFileInfo.ioFlXFndrInfo, ! 921: (UInt32 *) &searchInfo2->hFileInfo.ioFlXFndrInfo, ! 922: sizeof(FXInfo)/sizeof(UInt32)); ! 923: ! 924: if (matched == false) goto TestDone; ! 925: } ! 926: ! 927: // ! 928: // File logical length (data fork) ! 929: // ! 930: if (searchBits & fsSBFlLgLen) { ! 931: matched = CompareRange(catData.dataLogicalSize, searchInfo1->hFileInfo.ioFlLgLen, ! 932: searchInfo2->hFileInfo.ioFlLgLen); ! 933: if (matched == false) goto TestDone; ! 934: } ! 935: ! 936: // ! 937: // File physical length (data fork) ! 938: // ! 939: if (searchBits & fsSBFlPyLen) { ! 940: matched = CompareRange(catData.dataPhysicalSize, searchInfo1->hFileInfo.ioFlPyLen, ! 941: searchInfo2->hFileInfo.ioFlPyLen); ! 942: if (matched == false) goto TestDone; ! 943: } ! 944: ! 945: // ! 946: // File logical length (resource fork) ! 947: // ! 948: if (searchBits & fsSBFlRLgLen) { ! 949: matched = CompareRange(catData.rsrcLogicalSize, searchInfo1->hFileInfo.ioFlRLgLen, ! 950: searchInfo2->hFileInfo.ioFlRLgLen); ! 951: if (matched == false) goto TestDone; ! 952: } ! 953: ! 954: // ! 955: // File physical length (resource fork) ! 956: // ! 957: if (searchBits & fsSBFlRPyLen) { ! 958: matched = CompareRange(catData.rsrcPhysicalSize, searchInfo1->hFileInfo.ioFlRPyLen, ! 959: searchInfo2->hFileInfo.ioFlRPyLen); ! 960: if (matched == false) goto TestDone; ! 961: } ! 962: ! 963: // ! 964: // Create date ! 965: // ! 966: if (searchBits & fsSBFlCrDat) { ! 967: matched = CompareRange(catData.createDate, searchInfo1->hFileInfo.ioFlCrDat, ! 968: searchInfo2->hFileInfo.ioFlCrDat); ! 969: if (matched == false) goto TestDone; ! 970: } ! 971: ! 972: // ! 973: // Mod date ! 974: // ! 975: if (searchBits & fsSBFlMdDat) { ! 976: matched = CompareRange(catData.contentModDate, searchInfo1->hFileInfo.ioFlMdDat, ! 977: searchInfo2->hFileInfo.ioFlMdDat); ! 978: if (matched == false) goto TestDone; ! 979: } ! 980: ! 981: // ! 982: // Backup date ! 983: // ! 984: if (searchBits & fsSBFlBkDat) { ! 985: matched = CompareRange(catData.backupDate, searchInfo1->hFileInfo.ioFlBkDat, ! 986: searchInfo2->hFileInfo.ioFlBkDat); ! 987: } ! 988: ! 989: TestDone: ! 990: // ! 991: // Finally, determine whether we need to negate the sense of the match (i.e. find ! 992: // all objects that DON'T match). ! 993: // ! 994: if (searchBits & fsSBNegate) { ! 995: matched = !matched; ! 996: } ! 997: ! 998: return matched; ! 999: } ! 1000: #endif /* TARGET_OS_MAC */ ! 1001: ! 1002: ! 1003: ! 1004: Boolean CompareMasked(const UInt32 *thisValue, const UInt32 *compareData, ! 1005: const UInt32 *compareMask, UInt32 count) ! 1006: { ! 1007: Boolean matched; ! 1008: UInt32 i; ! 1009: ! 1010: matched = true; // Assume it will all match ! 1011: ! 1012: for (i=0; i<count; i++) { ! 1013: if (((*thisValue++ ^ *compareData++) & *compareMask++) != 0) { ! 1014: matched = false; ! 1015: break; ! 1016: } ! 1017: } ! 1018: ! 1019: return matched; ! 1020: } ! 1021: ! 1022: ! 1023: #if TARGET_OS_MAC ! 1024: Boolean CompareFullName(ConstStr31Param thisName, ConstStr31Param testName) ! 1025: { ! 1026: Str31 tempName; ! 1027: ! 1028: // ! 1029: // Make a quick check first. If the lengths differ, they can't possibly match. ! 1030: // ! 1031: if (thisName[0] != testName[0]) ! 1032: return false; ! 1033: ! 1034: // ! 1035: // Now make an upper case copy of thisName. ! 1036: // ! 1037: //�� Would it be better to skip making upper case versions of the names ! 1038: //�� and just call EqualString(thisName, testName, false, false)? I think it ! 1039: //�� should give the same result. ! 1040: // ! 1041: BlockMoveData(thisName, tempName, sizeof(Str31)); ! 1042: UprText( (Ptr)(tempName + 1), tempName[0]); ! 1043: ! 1044: // ! 1045: // Compare tempName and testName; they must be identical PStrings to match. ! 1046: // ! 1047: return PascalBinaryCompare(tempName, testName); ! 1048: } ! 1049: #endif /* TARGET_OS_MAC */ ! 1050: ! 1051: ! 1052: ! 1053: #if TARGET_OS_MAC ! 1054: Boolean ComparePartialName(ConstStr31Param thisName, ConstStr31Param substring) ! 1055: { ! 1056: Boolean matched; ! 1057: Str31 tempName; ! 1058: ! 1059: // ! 1060: // Make a quick check first. If the substring is longer than this object's name, ! 1061: // it can't possibly match. ! 1062: // ! 1063: if (substring[0] > thisName[0]) ! 1064: return false; ! 1065: ! 1066: // ! 1067: // Now make an upper case copy of thisName. ! 1068: // ! 1069: //�� Would it be better to skip making upper case versions of the names ! 1070: //�� and just call EqualString(thisName, testName, false, false)? I think it ! 1071: //�� should give the same result. ! 1072: // ! 1073: BlockMoveData(thisName, tempName, sizeof(Str31)); ! 1074: UprText( (Ptr)(tempName + 1), tempName[0]); ! 1075: ! 1076: // ! 1077: // Now see if substring is a substring of tempName. ! 1078: // ! 1079: matched = (PLstrstr(tempName, substring) != NULL); ! 1080: ! 1081: return matched; ! 1082: } ! 1083: #endif /* TARGET_OS_MAC */ ! 1084: ! 1085: ! 1086: ! 1087: //�� Same function appears in Volumes.c as CheckVolumeOffLine(), but the code is slightly different ! 1088: //�� we should delete one copy. ! 1089: #if TARGET_OS_MAC ! 1090: OSErr ExtOffLineCheck( ExtendedVCB *vcb ) ! 1091: { ! 1092: OSErr err; ! 1093: ! 1094: err = CheckExternalFileSystem(vcb); ! 1095: if (err == noErr) { ! 1096: if (vcb->vcbDrvNum != 0) ! 1097: LMSetReqstVol((Ptr) vcb); ! 1098: else ! 1099: err = volOffLinErr; ! 1100: } ! 1101: ! 1102: return err; ! 1103: } ! 1104: #endif ! 1105: ! 1106: ! 1107: void CatSearchTimerComplete(CatSearchState *state) ! 1108: { ! 1109: state->timerCompleted = true; ! 1110: } ! 1111: ! 1112: #if TARGET_OS_MAC ! 1113: static OSErr InitCatSearch( ExtendedVCB *volume, CSParam *pb, ScanState *scanState ) ! 1114: { ! 1115: OSErr err; ! 1116: FCB *fcb; ! 1117: BTREE_CB_TYPE *btcb; ! 1118: CatPosition *startingPosition; ! 1119: void *buffer; ! 1120: UInt32 bufferSize; ! 1121: FSVarsRec *fsVars; ! 1122: ! 1123: // ! 1124: // Set up pointers to the catalog's FCB and BTCB ! 1125: // ! 1126: fcb = GetFileControlBlock(volume->catalogRefNum); ! 1127: btcb = (BTREE_CB_TYPE *) fcb->fcbBTCBPtr; ! 1128: ! 1129: // ! 1130: // Flush all files on this volume so the BTrees will be up-to-date (since we only ! 1131: // read the BTree on disk, not what might be in the control blocks). ! 1132: // ! 1133: LMSetFlushOnly(0xFF); ! 1134: err = FlushVolume(volume); ! 1135: if (err != noErr) goto ErrorExit; ! 1136: ! 1137: // ! 1138: // Make sure the volume control files (especially the Catalog B-tree) gets flushed, ! 1139: // too, or else we'll be reading stale catalog data. ! 1140: // ! 1141: err = FlushVolumeBuffers(volume); ! 1142: if (err != noErr) goto ErrorExit; ! 1143: ! 1144: // ! 1145: // Use our internal optimization buffer unless the caller supplied a suitable one. ! 1146: // ! 1147: fsVars = (FSVarsRec *) LMGetFSMVars(); ! 1148: buffer = pb->ioOptBuffer; ! 1149: bufferSize = pb->ioOptBufSize; ! 1150: if (buffer == NULL || bufferSize < fsVars->gAttributesBufferSize) { ! 1151: buffer = fsVars->gAttributesBuffer; ! 1152: bufferSize = fsVars->gAttributesBufferSize; ! 1153: } ! 1154: ! 1155: // ! 1156: // Set up the scan state to start a new search, or resume a previous one. ! 1157: // ! 1158: startingPosition = (CatPosition *) &pb->ioCatPosition; ! 1159: if (startingPosition->writeCount == 0) { ! 1160: // ! 1161: // Starting a new search ! 1162: // ! 1163: err = BTScanInitialize(fcb, 0, 0, 0, buffer, bufferSize, scanState); ! 1164: } ! 1165: else { ! 1166: // ! 1167: // Resuming a previous search. Make sure the catalog hasn't changed ! 1168: // since the previous search. ! 1169: // ! 1170: if (startingPosition->writeCount != BTREE_WRITE_COUNT(btcb)) { ! 1171: startingPosition->writeCount = BTREE_WRITE_COUNT(btcb); // return the new write count ! 1172: err = catChangedErr; ! 1173: goto ErrorExit; ! 1174: } ! 1175: ! 1176: err = BTScanInitialize(fcb, startingPosition->nextNode, startingPosition->nextRecord, startingPosition->recordsFound, ! 1177: buffer, bufferSize, scanState); ! 1178: } ! 1179: ! 1180: ErrorExit: ! 1181: return err; ! 1182: } ! 1183: #endif /* TARGET_OS_MAC */ ! 1184: ! 1185: #if TARGET_OS_MAC ! 1186: static void UpdateCatPosition( const ExtendedVCB *volume, CatPosition *endingPosition, const ScanState *scanState ) ! 1187: { ! 1188: FCB *fcb; ! 1189: BTREE_CB_TYPE *btcb; ! 1190: ! 1191: // ! 1192: // Set up pointers to the catalog's FCB and BTCB ! 1193: // ! 1194: fcb = GetFileControlBlock(volume->catalogRefNum); ! 1195: btcb = (BTREE_CB_TYPE *) fcb->fcbBTCBPtr; ! 1196: ! 1197: // ! 1198: // Update the caller's CatPosition for the next time ! 1199: // ! 1200: endingPosition->writeCount = BTREE_WRITE_COUNT(btcb); ! 1201: BTScanTerminate(scanState, &endingPosition->nextNode, &endingPosition->nextRecord, &endingPosition->recordsFound); ! 1202: } ! 1203: #endif /* TARGET_OS_MAC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.