]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_search.c
xnu-201.19.3.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_search.c
index e606a3877b3fae1557c60f286351f563d3ae151a..df7c233c0aaed68c3d84ee33953f40740b715f47 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include "hfscommon/headers/FileMgrInternal.h"
 #include "hfscommon/headers/CatalogPrivate.h"
 #include "hfscommon/headers/HFSUnicodeWrappers.h"
-
-
-/* Private description used in hfs_search */
-/*
- * ============ W A R N I N G ! ============
- * DO NOT INCREASE THE SIZE OF THIS STRUCT!
- * It must match the size of the opaque
- * searchstate struct (in sys/attr.h).
- */
-struct SearchState {
-       long            searchBits;
-       BTreeIterator   btreeIterator;
-};
-typedef struct SearchState SearchState;
+#include "hfscommon/headers/BTreesPrivate.h"
+#include "hfscommon/headers/BTreeScanner.h"
 
 
 static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist        *alist, searchinfospec_t *searchInfo, void *attributeBuffer);
 
-Boolean CheckCriteria(ExtendedVCB *vcb, const SearchState *searchState,
+Boolean CheckCriteria(ExtendedVCB *vcb,
                        u_long searchBits, struct attrlist *attrList,
                        CatalogNodeData *cnp, CatalogKey *key,
                        searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2);
@@ -129,11 +117,7 @@ struct vop_searchfs_args *ap; /*
  struct searchstate *a_searchstate;
 */
 {
-       CatalogNodeData         cnode;
-       BTreeKey                        *key;
-       FSBufferDescriptor      btRecord;
        FCB*                            catalogFCB;
-       SearchState                     *searchState;
        searchinfospec_t        searchInfo1;
        searchinfospec_t        searchInfo2;
        void                            *attributesBuffer;
@@ -143,7 +127,13 @@ struct vop_searchfs_args *ap; /*
        u_long                          fixedBlockSize;
        u_long                          eachReturnBufferSize;
        struct proc                     *p = current_proc();
-       u_long                          nodesToCheck = 30;      /* After we search 30 nodes we must give up time */
+       CatalogNodeData         myCNodeData;
+       CatalogNodeData *       myCNodeDataPtr;
+       CatalogKey * myCurrentKeyPtr;
+       CatalogRecord * myCurrentDataPtr;
+       CatPosition * myCatPositionPtr;
+       BTScanState myBTScanState;
+       Boolean                         timerExpired = false;
        u_long                          lastNodeNum = 0XFFFFFFFF;
        ExtendedVCB                     *vcb = VTOVCB(ap->a_vp);
        int                                     err = E_NONE;
@@ -160,19 +150,6 @@ struct vop_searchfs_args *ap; /*
                return (EINVAL);
 
        isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
-       searchState = (SearchState *)ap->a_searchstate;
-
-       /*
-        * Check if this is the first time we are being called.
-        * If it is, allocate SearchState and we'll move it to the users space on exit
-        */
-       if ( ap->a_options & SRCHFS_START ) {
-               bzero( (caddr_t)searchState, sizeof(SearchState) );
-               operation = kBTreeFirstRecord;
-               ap->a_options &= ~SRCHFS_START;
-       } else {
-               operation = kBTreeCurrentRecord;
-       }
 
        /* UnPack the search boundries, searchInfo1, searchInfo2 */
        err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo1, ap->a_searchparams1 );
@@ -180,16 +157,6 @@ struct vop_searchfs_args *ap; /*
        err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo2, ap->a_searchparams2 );
        if (err) return err;
 
-       btRecord.itemCount = 1;
-       if (isHFSPlus) {
-               btRecord.itemSize = sizeof(cnode);
-               btRecord.bufferAddress = &cnode;
-       } else {
-               btRecord.itemSize = sizeof(HFSCatalogFile);
-               btRecord.bufferAddress = &cnode.cnd_extra;
-       }
-       catalogFCB = VTOFCB( vcb->catalogRefNum );
-       key = (BTreeKey*) &(searchState->btreeIterator.key);
        fixedBlockSize = sizeof(u_long) + AttributeBlockSize( ap->a_returnattrs );      /* u_long for length longword */
        eachReturnBufferSize = fixedBlockSize;
        
@@ -205,41 +172,102 @@ struct vop_searchfs_args *ap; /*
                goto ExitThisRoutine;
        };
 
+       catalogFCB = VTOFCB( vcb->catalogRefNum );
+       myCurrentKeyPtr = NULL;
+       myCurrentDataPtr = NULL;
+       myCatPositionPtr = (CatPosition *)ap->a_searchstate;
+
+       if (ap->a_options & SRCHFS_START) {
+               /* Starting a new search. */
+               ap->a_options &= ~SRCHFS_START;
+               bzero( (caddr_t)myCatPositionPtr, sizeof( *myCatPositionPtr ) );
+               err = BTScanInitialize(catalogFCB, 0, 0, 0, kCatSearchBufferSize, &myBTScanState);
+       } else {
+               /* Resuming a search. */
+               err = BTScanInitialize(catalogFCB, myCatPositionPtr->nextNode, 
+                                       myCatPositionPtr->nextRecord, 
+                                       myCatPositionPtr->recordsFound,
+                                       kCatSearchBufferSize, 
+                                       &myBTScanState);
+#if 0
+               /* Make sure Catalog hasn't changed. */
+               if (err == 0
+               &&  myCatPositionPtr->writeCount != myBTScanState.btcb->writeCount) {
+                       myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
+                       err = EBUSY; /* catChangedErr */
+               }
+#endif
+       }
+
+       /* Unlock catalog b-tree */
+       (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p);
+       if (err)
+               goto ExitThisRoutine;
+
        /*
-        * Iterate over all the catalog btree records
+        * Check all the catalog btree records...
+        *   return the attributes for matching items
         */
-       
-       err = BTIterateRecord( catalogFCB, operation, &(searchState->btreeIterator), &btRecord, &recordSize );
+       for (;;) {
+               struct timeval myCurrentTime;
+               struct timeval myElapsedTime;
+               
+               err = BTScanNextRecord(&myBTScanState, timerExpired, 
+                       (void **)&myCurrentKeyPtr, (void **)&myCurrentDataPtr, 
+                       NULL);
+               if (err)
+                       break;
 
-       while( err == E_NONE ) {
-               if (!isHFSPlus)
-                       CopyCatalogNodeData(vcb, (CatalogRecord*)&cnode.cnd_extra, &cnode);
-       
-               if ( CheckCriteria( vcb, searchState, ap->a_options, ap->a_searchattrs, &cnode,
-                                                       (CatalogKey *)key, &searchInfo1, &searchInfo2 ) &&
-                        CheckAccess(&cnode, (CatalogKey *)key, ap->a_uio->uio_procp)) {
-                       err = InsertMatch(ap->a_vp, ap->a_uio, &cnode, (CatalogKey *)key,
-                                         ap->a_returnattrs, attributesBuffer, variableBuffer,
-                                         eachReturnBufferSize, ap->a_nummatches);
-                       if ( err != E_NONE )
-                               break;
+               if ( isHFSPlus ) {
+                       // HFSPlus vols have CatalogRecords that map exactly to CatalogNodeData so there is no need 
+                       // to copy.
+                       myCNodeDataPtr = (CatalogNodeData *) myCurrentDataPtr;
+               } else {
+                       CopyCatalogNodeData( vcb, myCurrentDataPtr, &myCNodeData );
+                       myCNodeDataPtr = &myCNodeData;
                }
-
-               err = BTIterateRecord( catalogFCB, kBTreeNextRecord, &(searchState->btreeIterator), &btRecord, &recordSize );
-               
-                       if  ( *(ap->a_nummatches) >= ap->a_maxmatches )
+                       
+               if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, myCNodeDataPtr,
+                                 myCurrentKeyPtr, &searchInfo1, &searchInfo2) &&
+                   CheckAccess(myCNodeDataPtr, myCurrentKeyPtr, ap->a_uio->uio_procp)) {
+
+                       err = InsertMatch(ap->a_vp, ap->a_uio, myCNodeDataPtr, 
+                                         myCurrentKeyPtr, ap->a_returnattrs,
+                                         attributesBuffer, variableBuffer,
+                                         eachReturnBufferSize, ap->a_nummatches);
+                       if (err) {
+                               /*
+                                * The last match didn't fit so come back
+                                * to this record on the next trip.
+                                */
+                               --myBTScanState.recordsFound;
+                               --myBTScanState.recordNum;
                                break;
+                       }
+                       if (*(ap->a_nummatches) >= ap->a_maxmatches)
+                               break;
+               }
 
-               if ( searchState->btreeIterator.hint.nodeNum != lastNodeNum ) {
-                       lastNodeNum = searchState->btreeIterator.hint.nodeNum;
-                       if ( --nodesToCheck == 0 )
-                               break;  /* We must leave the kernel to give up time */
+               /*
+                * Check our elapsed time and bail if we've hit the max.
+                * The idea here is to throttle the amount of time we
+                * spend in the kernel.
+                */
+               myCurrentTime = time;
+               timersub(&myCurrentTime, &myBTScanState.startTime, &myElapsedTime);
+               /* Note: assumes kMaxMicroSecsInKernel is less than 1,000,000 */
+               if (myElapsedTime.tv_sec > 0
+               ||  myElapsedTime.tv_usec >= kMaxMicroSecsInKernel) {
+                       timerExpired = true;
                }
        }
 
-       /* Unlock catalog b-tree */
-       (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p );
+       /* Update catalog position */
+       myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
 
+       BTScanTerminate(&myBTScanState, &myCatPositionPtr->nextNode, 
+                       &myCatPositionPtr->nextRecord, 
+                       &myCatPositionPtr->recordsFound);
 
        if ( err == E_NONE ) {
                err = EAGAIN;   /* signal to the user to call searchfs again */
@@ -250,12 +278,14 @@ struct vop_searchfs_args *ap; /*
                        err = ENOBUFS;
        } else if ( err == btNotFound ) {
                err = E_NONE;   /* the entire disk has been searched */
+       } else if ( err == fsBTTimeOutErr ) {
+               err = EAGAIN;
        }
 
 ExitThisRoutine:
         FREE( attributesBuffer, M_TEMP );
 
-       return( err );
+       return (MacToVFSError(err));
 }
 
 
@@ -330,7 +360,7 @@ CheckAccess(CatalogNodeData *cnp, CatalogKey *key, struct proc *p)
 }
 
 Boolean
-CheckCriteria( ExtendedVCB *vcb, const SearchState *searchState, u_long searchBits,
+CheckCriteria( ExtendedVCB *vcb, u_long searchBits,
                struct attrlist *attrList, CatalogNodeData *cnp, CatalogKey *key,
                searchinfospec_t  *searchInfo1, searchinfospec_t *searchInfo2 )
 {
@@ -395,11 +425,11 @@ CheckCriteria( ExtendedVCB *vcb, const SearchState *searchState, u_long searchBi
        
        /* Now that we have a record worth searching, see if it matches the search attributes */
        if (cnp->cnd_type == kCatalogFileNode) {
-               if ((attrList->dirattr & ~ATTR_FILE_VALIDMASK) != 0) {  /* attr we do know about  */
+               if ((attrList->fileattr & ~ATTR_FILE_VALIDMASK) != 0) { /* attr we do know about  */
                        matched = false;
                        goto TestDone;
                }
-               else if ((attrList->dirattr & ATTR_FILE_VALIDMASK) != 0) {
+               else if ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) {
                searchAttributes = attrList->fileattr;
        
                /* File logical length (data fork) */