Beispiel #1
0
//--	Delete all extents in extent file that have the ID given.
static OSErr  DeleteExtents( ExtendedVCB *vcb, u_int32_t fileID, Boolean isHFSPlus )
{
	FCB *				fcb;
	ExtentKey *			extentKeyPtr;
	ExtentRecord		extentData;
	BTreeIterator		btIterator;
	FSBufferDescriptor	btRecord;
	u_int16_t			btRecordSize;
	OSErr				err;

	fcb = GetFileControlBlock(vcb->extentsRefNum);

	(void) BTInvalidateHint(&btIterator);
	extentKeyPtr = (ExtentKey*) &btIterator.key;
	btRecord.bufferAddress = &extentData;
	btRecord.itemCount = 1;

	//	The algorithm is to position the BTree just before any extent records for fileID.
	//	Then just keep getting successive records.  If the record is still for fileID,
	//	then delete it.
	
	if (isHFSPlus) {
		btRecord.itemSize = sizeof(HFSPlusExtentRecord);

		extentKeyPtr->hfsPlus.keyLength	 = kHFSPlusExtentKeyMaximumLength;
		extentKeyPtr->hfsPlus.forkType	 = 0;
		extentKeyPtr->hfsPlus.pad		 = 0;
		extentKeyPtr->hfsPlus.fileID	 = fileID;
		extentKeyPtr->hfsPlus.startBlock = 0;
	}
	else {
		btRecord.itemSize = sizeof(HFSExtentRecord);

		extentKeyPtr->hfs.keyLength	 = kHFSExtentKeyMaximumLength;
		extentKeyPtr->hfs.forkType	 = 0;
		extentKeyPtr->hfs.fileID	 = fileID;
		extentKeyPtr->hfs.startBlock = 0;
	}

	err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
	if ( err != btNotFound )
	{
		if (err == noErr) {		//	Did we find a bogus extent record?
			err = cmBadNews;	//	Yes, so indicate things are messed up.
		}
		
		return err;				//	Got some unexpected error, so return it
	}

	do
	{
		BTreeIterator 		tmpIterator;
		HFSCatalogNodeID	foundFileID;

		err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
		if ( err != noErr )
		{
			if (err == btNotFound)	//	If we hit the end of the BTree
				err = noErr;		//		then it's OK
				
			break;					//	We're done now.
		}
		
		foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
		if ( foundFileID != fileID )
			break;					//	numbers don't match, we must be done

		tmpIterator = btIterator;
		err = BTDeleteRecord( fcb, &tmpIterator );
		if (err != noErr)
			break;
	}	while ( true );
	
	return( err );
}
Beispiel #2
0
/* 
 * This is a helper function that counts the total number of valid 
 * extents in all the overflow extent records for given fileID 
 * in overflow extents btree
 */
static errno_t
hfs_count_overflow_extents(struct hfsmount *hfsmp, uint32_t fileID, uint32_t *num_extents)
{
	int error;
	FCB *fcb;
	struct BTreeIterator *iterator = NULL;
	FSBufferDescriptor btdata;
	HFSPlusExtentKey *extentKey;
	HFSPlusExtentRecord extentData;
	uint32_t extent_count = 0;
	int i;

	fcb = VTOF(hfsmp->hfs_extents_vp);
	MALLOC(iterator, struct BTreeIterator *, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK | M_ZERO);
	
	extentKey = (HFSPlusExtentKey *) &iterator->key;	
	extentKey->keyLength = kHFSPlusExtentKeyMaximumLength;
	extentKey->forkType = kHFSDataForkType;
	extentKey->fileID = fileID;
	extentKey->startBlock = 0;

	btdata.bufferAddress = &extentData;
	btdata.itemSize = sizeof(HFSPlusExtentRecord);
	btdata.itemCount = 1;

	/* Search for overflow extent record */
	error = BTSearchRecord(fcb, iterator, &btdata, NULL, iterator);
	
	/*
	 * We used startBlock of zero, so we will not find any records and errors
	 * are expected.  It will also position the iterator just before the first 
	 * overflow extent record for given fileID (if any). 
	 */
	if (error && error != fsBTRecordNotFoundErr && error != fsBTEndOfIterationErr)
			goto out;
	error = 0;

	for (;;) {
		
		if (msleep(NULL, NULL, PINOD | PCATCH,
				   "hfs_fsinfo", NULL) == EINTR) {
			error = EINTR;
			break;
		}
		
		error = BTIterateRecord(fcb, kBTreeNextRecord, iterator, &btdata, NULL);
		if (error != 0) {
			/* These are expected errors, so mask them */
			if (error == fsBTRecordNotFoundErr || error == fsBTEndOfIterationErr) {
				error = 0;
			}
			break;
		}

		/* If we encounter different fileID, stop the iteration */
		if (extentKey->fileID != fileID) {
			break;
		}
		
		if (extentKey->forkType != kHFSDataForkType)
			break;
		
		/* This is our record of interest; only count the datafork extents. */
		for (i = 0; i < kHFSPlusExtentDensity; i++) {
			if (extentData[i].blockCount == 0) {
				break;
			}
			extent_count++;
		}
	}

out:
	FREE(iterator, M_TEMP);

	if (error == 0) {
		*num_extents = extent_count;
	}
	return MacToVFSError(error);
}
Beispiel #3
0
static OSErr  MoveExtents( ExtendedVCB *vcb, u_int32_t srcFileID, u_int32_t destFileID, Boolean isHFSPlus )
{
	FCB *				fcb;
	ExtentsRecBuffer	extentsBuffer[kNumExtentsToCache];
	ExtentKey *			extentKeyPtr;
	ExtentRecord		extentData;
	BTreeIterator		btIterator;
	FSBufferDescriptor	btRecord;
	u_int16_t			btKeySize;
	u_int16_t			btRecordSize;
	int16_t				i, j;
	OSErr				err;
	

	fcb = GetFileControlBlock(vcb->extentsRefNum);
	
	(void) BTInvalidateHint(&btIterator);
	extentKeyPtr = (ExtentKey*) &btIterator.key;
	btRecord.bufferAddress = &extentData;
	btRecord.itemCount = 1;

	//--	Collect the extent records

	//
	//	A search on the following key will cause the BTree to be positioned immediately
	//	before the first extent record for file #srcFileID, but not actually positioned
	//	on any record.  This is because there cannot be an extent record with FABN = 0
	//	(the first extent of the fork, which would be in the catalog entry, not an extent
	//	record).
	//
	//	Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
	//
	if (isHFSPlus) {
		btRecord.itemSize = sizeof(HFSPlusExtentRecord);
		btKeySize = sizeof(HFSPlusExtentKey);

		extentKeyPtr->hfsPlus.keyLength	 = kHFSPlusExtentKeyMaximumLength;
		extentKeyPtr->hfsPlus.forkType	 = 0;
		extentKeyPtr->hfsPlus.pad		 = 0;
		extentKeyPtr->hfsPlus.fileID	 = srcFileID;
		extentKeyPtr->hfsPlus.startBlock = 0;
	}
	else {
		btRecord.itemSize = sizeof(HFSExtentRecord);
		btKeySize = sizeof(HFSExtentKey);

		extentKeyPtr->hfs.keyLength	 = kHFSExtentKeyMaximumLength;
		extentKeyPtr->hfs.forkType	 = 0;
		extentKeyPtr->hfs.fileID	 = srcFileID;
		extentKeyPtr->hfs.startBlock = 0;
	}
	
	//
	//	We do an initial BTSearchRecord to position the BTree's iterator just before any extent
	//	records for srcFileID.  We then do a few BTIterateRecord and BTInsertRecord of those found
	//	records, but with destFileID as the file number in the key.  Keep doing this sequence of
	//	BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
	//	no more extent records in the tree.
	//
	//	Basically, we're copying records kNumExtentsToCache at a time.  The copies have their file ID
	//	set to destFileID.
	//
	//	This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord.  If it
	//	_did_ effect the iterator, then we would need to do a BTSearchRecord before each series
	//	of BTIterateRecord.  We'd need to set up the key for BTSearchRecord to find the last record
	//	we found, so that BTIterateRecord would get the next one (the first we haven't processed).
	//

	err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
	
	//	We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
	if (err != btNotFound)
	{
		if ( DEBUG_BUILD )
			DebugStr("Unexpected error from SearchBTreeRecord");
		
		if (err == noErr)			//	If we found such a bogus extent record, then the tree is really messed up
			err = cmBadNews;		//	so return an error that conveys the disk is hosed.
		
		return err;
	}

	do
	{
		btRecord.bufferAddress = &extentData;
		btRecord.itemCount = 1;

		for ( i=0 ; i<kNumExtentsToCache ; i++ )
		{
			HFSCatalogNodeID	foundFileID;

			err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
			if ( err == btNotFound )		//	Did we run out of extent records in the extents tree?
				break;						//	if xkrFNum(A0) is cleared on this error, then this test is bogus!
			else if ( err != noErr )
				return( err );				//	must be ioError
			
			foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
			if ( foundFileID == srcFileID )
			{
				CopyExtentInfo(extentKeyPtr, &extentData, extentsBuffer, i);
			}
			else
			{
				break;
			}
		}
		
		//--	edit each extent key, and reinsert each extent record in the extent file
		if (isHFSPlus)
			btRecordSize = sizeof(HFSPlusExtentRecord);
		else
			btRecordSize = sizeof(HFSExtentRecord);

		for ( j=0 ; j<i ; j++ )
		{
			BTreeIterator tmpIterator;

			if (isHFSPlus)
				extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID;	//	change only the id in the key to dest ID
			else
				extentsBuffer[j].extentKey.hfs.fileID = destFileID;	//	change only the id in the key to dest ID

			// get iterator and buffer descriptor ready...
			(void) BTInvalidateHint(&tmpIterator);
			BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator.key, btKeySize);
			btRecord.bufferAddress = &(extentsBuffer[j].extentData);

			err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize);
			if ( err != noErr )
			{									//	parse the error
				if ( err == btExists )
				{
					if ( DEBUG_BUILD )
						DebugStr("Can't insert record -- already exists");
					return( cmBadNews );
				}
				else
					return( err );
			}
		}
		
		//--	okay, done with this buffered batch, go get the next set of extent records
		//	If our buffer is not full, we must be done, or recieved an error
		
		if ( i != kNumExtentsToCache )			//	if the buffer is not full, we must be done
		{
			err = DeleteExtents( vcb, srcFileID, isHFSPlus );	//	Now delete all the extent entries with the sourceID
			if ( DEBUG_BUILD && err != noErr )
				DebugStr("Error from DeleteExtents");
			break;									//	we're done!
		}
	} while ( true );
	
	return( err );
}
OSErr
LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr,
						CatalogRecord *dataPtr, u_int32_t *newHint)
{
	OSErr				result;
	CatalogName 		*nodeName = NULL;
	HFSCatalogNodeID	threadParentID;
	u_int16_t tempSize;
	FSBufferDescriptor	 btRecord;
	BTreeIterator		 searchIterator; 
	FCB			*fcb;

	bzero(&searchIterator, sizeof(searchIterator));

	fcb = GetFileControlBlock(volume->catalogRefNum);

	btRecord.bufferAddress = dataPtr;
	btRecord.itemCount = 1;
	btRecord.itemSize = sizeof(CatalogRecord);

	searchIterator.hint.nodeNum = hint;

	bcopy(keyPtr, &searchIterator.key, sizeof(CatalogKey));
	
	result = BTSearchRecord( fcb, &searchIterator, &btRecord, &tempSize, &searchIterator );

	if (result == noErr)
	{
		*newHint = searchIterator.hint.nodeNum;

		BlockMoveData(&searchIterator.key, keyPtr, sizeof(CatalogKey));
	}

	if (result == btNotFound)
		result = cmNotFound;	
	ReturnIfError(result);
	
	// if we got a thread record, then go look up real record
	switch ( dataPtr->recordType )
	{
		case kHFSFileThreadRecord:
		case kHFSFolderThreadRecord:
			threadParentID = dataPtr->hfsThread.parentID;
			nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
			break;

		case kHFSPlusFileThreadRecord:
		case kHFSPlusFolderThreadRecord:
			threadParentID = dataPtr->hfsPlusThread.parentID;
			nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;	
			break;

		default:
			threadParentID = 0;
			break;
	}
	
	if ( threadParentID )		// found a thread
		result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
	
	return result;
}