/*
- * 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);
struct searchstate *a_searchstate;
*/
{
- CatalogNodeData cnode;
- BTreeKey *key;
- FSBufferDescriptor btRecord;
FCB* catalogFCB;
- SearchState *searchState;
searchinfospec_t searchInfo1;
searchinfospec_t searchInfo2;
void *attributesBuffer;
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;
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 );
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;
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 */
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));
}
}
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 )
{
/* 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) */