Scavenger.h   [plain text]


/*
 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/* Scavenger.h */

#ifndef __SCAVENGER__
#define __SCAVENGER__

#define pascal

#include "SRuntime.h"
#include "BTree.h"
#include "BTreePrivate.h"
#include "CheckHFS.h"
#include "BTreeScanner.h"
#include "hfs_endian.h"
#include "../fsck_debug.h"

#include <assert.h>
#include <sys/xattr.h>
#include <sys/acl.h>
#include <sys/kauth.h>
#include <sys/errno.h>
#include <sys/syslimits.h>

#ifdef __cplusplus
extern	"C" {
#endif


#define kFSCKMountVersion	0x6673636B	/* 'fsck' made changes */

enum {
	Log2BlkLo				= 9,					// number of left shifts to convert bytes to block.lo
	Log2BlkHi				= 23					// number of right shifts to convert bytes to block.hi
};

enum {
	kNoHint						= 0
};


//
// Misc constants
//

/* IO size for reading or writing disk blocks */
#define DISK_IOSIZE	32768

#define kMaxReScan	3	/* max times to re-scan volume on repair success */

#define	kBTreeHeaderUserBytes	128

#define	kBusErrorValue	0x50FF8001

//ее Danger! This should not be hard coded
#define	kMaxClumpSize	0x100000	/* max clump size is 1MB (2048 btree nodes) */

#define	MDB_FNum	1				/* file number representing the MDB */
#define	AMDB_FNum	-1				/* file number representing the alternate MDB */
#define	VBM_FNum	2				/* file number representing the volume bit map */
#define	MDB_BlkN	2				/* logical block number for the MDB */

#define kCalculatedExtentRefNum			( 0 )
#define kCalculatedCatalogRefNum		( 1*sizeof(SFCB) )
#define kCalculatedAllocationsRefNum	( 2*sizeof(SFCB) )
#define kCalculatedAttributesRefNum		( 3*sizeof(SFCB) )
#define kCalculatedStartupRefNum		( 4*sizeof(SFCB) )
#define kCalculatedRepairRefNum			( 5*sizeof(SFCB) )

#define	Max_ABSiz	0x7FFFFE00		/* max allocation block size (multiple of 512 */
#define	Blk_Size	512				/* size of a logical block */
#define kHFSBlockSize 512			/* HFS block size */

// only the lower 7 bits are considered to be invalid, all others are valid -djb
#define	VAtrb_Msk	0x007F			/* volume attribute mask - invalid bits */
#define	VAtrb_DFlt	0x0100			/* default volume attribute flags */
#define	VAtrb_Cons	0x0100			/* volume consistency flag */
#define kHFSCatalogNodeIDsReused 0x1000		

/*
 *	File type and creator for symbolic links (from xnu/bsd/hfs/hfs.h)
 */
enum {
	kSymLinkFileType  = 0x736C6E6B,	/* 'slnk' */
	kSymLinkCreator   = 0x72686170	/* 'rhap' */
};

/*
 *	File type and creator for TextEdit documents
 */
enum {
	kTextFileType		= 0x54455854,	/* 'TEXT' */
	kTextFileCreator	= 0x74747874,	/* 'ttxt' */
};

/*------------------------------------------------------------------------------
 BTree data structures
------------------------------------------------------------------------------*/

/* misc BTree constants */

#define	BTMaxDepth	8				/* max tree depth */
#define	Num_HRecs	3				/* number of records in BTree Header node */
#define	Num_MRecs	1				/* number of records in BTree Map node */



//	DFA extensions to the HFS/HFS+ BTreeControlBlock
typedef struct BTreeExtensionsRec
{
	Ptr 				BTCBMPtr;			//	pointer to scavenger BTree bit map
	UInt32				BTCBMSize;			//	size of the bitmap, bytes
	BTreeControlBlock	*altBTCB;			//	BTCB DFA builds up
	UInt32				realFreeNodeCount;	//	Number of real free nodes, taken from disk, for more accurate progress information
} BTreeExtensionsRec;


	
/*
 * Scavenger BTree Path Record (STPR)
 */
typedef struct STPR {
	UInt32			TPRNodeN;		/* node number */
	SInt16			TPRRIndx;		/* record index */
	SInt16			unused;			/* not used - makes debugging easier */
	UInt32			TPRLtSib;		/* node number of left sibling node */
	UInt32			TPRRtSib;		/* node number of right sibling node */
	} STPR, *STPRPtr;
	
typedef	STPR SBTPT[BTMaxDepth]; 		/* BTree path table */
	
#define	LenSBTPT	( sizeof(STPR) * BTMaxDepth )	/* length of BTree Path Table */




/*------------------------------------------------------------------------------
 CM (Catalog Manager) data structures
 ------------------------------------------------------------------------------*/

//
//	Misc constants
//
#define CMMaxDepth	100				/* max catalog depth (Same as Finder 7.0) */

#define fNameLocked 4096

union CatalogName {
	Str31 							pstr;
	HFSUniStr255 					ustr;
};
typedef union CatalogName				CatalogName;
	
//
//	Scavenger Directory Path Record (SDPR)
//
typedef struct SDPR {
	UInt32				directoryID;		//	directory ID
	UInt32				offspringIndex;		//	offspring index
	UInt32				directoryHint;		//	BTree hint for directory record
	long				threadHint;			//	BTree hint for thread record
	HFSCatalogNodeID	parentDirID;		//	parent directory ID
	CatalogName			directoryName;		//	directory CName
} SDPR;
	
typedef	SDPR SDPT[CMMaxDepth]; 			//	directory path table
	
#define	LenSDPT	( sizeof(SDPR) * CMMaxDepth )	//	length of Tree Path Table


enum {
//	kInvalidMRUCacheKey			= -1L,							/* flag to denote current MRU cache key is invalid*/
	kDefaultNumMRUCacheBlocks	= 16							/* default number of blocks in each cache*/
};


/*
 * UTCacheReadIP and UTCacheWriteIP cacheOption
 */

enum {
	noCacheBit   = 5,	/* don't cache this please */
	noCacheMask  = 0x0020,
	rdVerifyBit  = 6,	/* read verify */
	rdVerifyMask = 0x0040
};


/*------------------------------------------------------------------------------
 Low-level File System Error codes 
------------------------------------------------------------------------------*/

/* The DCE bits are defined as follows (for the word of flags): */

enum
{
	Is_AppleTalk		= 0,
	Is_Agent			= 1,			// future use
	FollowsNewRules		= 2,			// New DRVR Rules Bit
	Is_Open				= 5,
	Is_Ram_Based		= 6,
	Is_Active			= 7,
	Read_Enable			= 8,
	Write_Enable		= 9,
	Control_Enable		= 10,
	Status_Enable		= 11,
	Needs_Goodbye		= 12,
	Needs_Time			= 13,
	Needs_Lock			= 14,

	Is_AppleTalk_Mask	= 1 << Is_AppleTalk,
	Is_Agent_Mask		= 1 << Is_Agent,
	FollowsRules_Mask	= 1 << FollowsNewRules,
	Is_Open_Mask		= 1 << Is_Open,
	Is_Ram_Based_Mask	= 1 << Is_Ram_Based,
	Is_Active_Mask		= 1 << Is_Active,
	Read_Enable_Mask	= 1 << Read_Enable,
	Write_Enable_Mask	= 1 << Write_Enable,
	Control_Enable_Mask	= 1 << Control_Enable,
	Status_Enable_Mask	= 1 << Status_Enable,
	Needs_Goodbye_Mask	= 1 << Needs_Goodbye,
	Needs_Time_Mask		= 1 << Needs_Time,
	Needs_Lock_Mask		= 1 << Needs_Lock
};

enum {
	cdInternalErr					= -1312,		//	internal CheckDisk error
	cdVolumeNotFoundErr				= -1313,		//	cound not find volume (could be offline)
	cdCannotReadErr					= -1314,		//	unable to read from disk
	cdCannotWriteErr				= -1315,		//	unable to write to disk
	cdNotHFSVolumeErr				= -1316,		//	not an HFS disk
	cdUnrepairableErr				= -1317,		//	volume needs major repairs that CheckDisk cannot fix
	cdRepairFailedErr				= -1318,		//	repair failed
	cdUserCanceledErr				= -1319,		//	user interrupt
	cdVolumeInUseErr				= -1320,		//	volume modifed by another app
	cdNeedsRepairsErr				= -1321,		//	volume needs repairs (see repairInfo for additional info)
	cdReMountErr					= -1322,		//	Cannot remount volume
	cdUnknownProcessesErr			= -1323,		//	Volume cannot be unmounted and unknown processes are running
	cdDamagedWrapperErr				= -1324,		//	HFS Wrapper damaged error.
	cdIncompatibleOSErr				= -1325,		//	Current OS version is incompatible
	cdMemoryFullErr					= -1326			//	not enough memory to check disk
};


enum {
	fsDSIntErr	= -127	/* non-hardware Internal file system error */
};

//	Repair Info - additional info returned when a repair is attempted
enum {
	kFileSharingEnabled		= 0x00000001,
	kDiskIsLocked			= 0x00000002,
	kDiskIsBoot			= 0x00000004,
	kDiskHasOpenFiles		= 0x00000008,
	kVolumeHadOverlappingExtents	= 0x00000010,	// repairLevelSomeDataLoss
	kVolumeClean			= 0x00000020,

	kRepairsWereMade		= 0x80000000
};

//	Input parameters to CheckDisk
enum
{
	ignoreRunningProcessesMask		= 0x00000001,	//	Assumes caller has shut down processes
	checkDiskVersionMask			= 0x00000004	//	Will just return back the version in repairInfo.
};

//	Message types, so the user can treat and display accordingly
enum {
	kStatusMessage					= 0x0000,
	kTitleMessage					= 0x0001,
	kErrorMessage					= 0x0002
};

//	<10> Current stage of CheckDisk passed to cancel proc.
//	File System is marked busy during kRepairStage, so WaitNextEvent and I/O cannot be done during this stage.

enum {
	kHFSStage						= 0,
	kRepairStage,
	kVerifyStage,
	kAboutToRepairStage
};

//	Resource ID of 'STR ' resource containing the name of of the folder to create aliases to damaged files.
enum {
	rDamagedFilesDirSTRid			= -20886
};

//	Type of volume
enum {
	kUnknownVolumeType 	= 0,
	kHFSVolumeType,
	kEmbededHFSPlusVolumeType,
	kPureHFSPlusVolumeType
};


enum {
	kStatusLines	= 131,
	kFirstError		= 500,
	
	kHighLevelInfo	= 1100,
	kBasicInfo		= 1200,
	kErrorInfo		= 1202,

	kErrorBase		= -1310
};


/*------------------------------------------------------------------------------
 Minor Repair Interface (records compiled during scavenge, later repaired)
 Note that not all repair types use all of these fields.
 -----------------------------------------------------------------------------*/
 
 typedef struct	RepairOrder			/* a node describing a needed minor repair */
 {
 	struct RepairOrder	*link;	/* link to next node, or NULL */
	SInt16			type;	/* type of error, as an error code (E_DirVal etc) */
	SInt16		forkType;	/* which file fork */
	UInt64		correct;	/* correct valence */
	UInt64		incorrect;	/* valence as found in volume (for consistency chk) */
	UInt32		maskBit;	/* incorrect bit */
	UInt32		hint;		/* B-tree node hint */
	UInt32		parid;		/* parent ID */
	unsigned char name[1];	/* dir or file name */
 } RepairOrder, *RepairOrderPtr;


 typedef struct	EmbededVolDescription
 {
 	SInt16				drAlBlSt;
	UInt16 				drEmbedSigWord;
 	HFSExtentDescriptor	drEmbedExtent;
 } EmbededVolDescription;


// define the correct drive queue structure
typedef struct ExtendedDrvQueue
{
	char dQVolumeLocked;
	char dQDiskInDrive;
	char dQUsedInternally;
	char dQDiskIsSingleSided;
	QElemPtr qLink;
	short qType;
	short dQDrive;
	short dQRefNum;
	short dQFSID;
	short dQDrvSz;
	short dQDrvSz2;
}ExtendedDrvQueue;


/*------------------------------------------------------------------------------
 Scavenger Global Area - (SGlob) 
------------------------------------------------------------------------------*/
typedef struct MissingThread
{
	struct MissingThread  *link;		/* link to next node, or NULL */
	UInt32                threadID;
	HFSPlusCatalogKey     nextKey;
	HFSPlusCatalogThread  thread;
} MissingThread;

#define kDataFork	0
#define kRsrcFork	(-1)
#define kEAData		1

struct ExtentInfo {
	HFSCatalogNodeID fileID;
	UInt32	startBlock;
	UInt32 	blockCount;
	UInt32	newStartBlock;
	char *  attrname;
	UInt8	forkType;
	/* didRepair stores the result of moving of overlap extent and is used 
	 * to decide which disk blocks (original blocks or blocks allocated for 
	 * for new extent location) should be marked used and free.
	 */
	Boolean didRepair;		
};
typedef struct ExtentInfo ExtentInfo;

struct ExtentsTable {
	UInt32 							count;
	ExtentInfo 						extentInfo[1];
};
typedef struct ExtentsTable ExtentsTable;


struct FileIdentifier {
	Boolean 						hasThread;
	HFSCatalogNodeID 				fileID;
	HFSCatalogNodeID 				parID;			//	Used for files on HFS volumes without threads
	Str31		 					name;			//	Used for files on HFS volumes without threads
};
typedef struct FileIdentifier FileIdentifier;

struct FileIdentifierTable {
	UInt32 							count;
	FileIdentifier 					fileIdentifier[1];
};
typedef struct FileIdentifierTable FileIdentifierTable;

/* Universal Extent Key */

union ExtentKey {
	HFSExtentKey 					hfs;
	HFSPlusExtentKey 				hfsPlus;
};
typedef union ExtentKey					ExtentKey;
/* Universal extent descriptor */

union ExtentDescriptor {
	HFSExtentDescriptor 			hfs;
	HFSPlusExtentDescriptor 		hfsPlus;
};
typedef union ExtentDescriptor			ExtentDescriptor;
/* Universal extent record */

union ExtentRecord {
	HFSExtentRecord 				hfs;
	HFSPlusExtentRecord 			hfsPlus;
};
typedef union ExtentRecord				ExtentRecord;
/* Universal catalog key */

union CatalogKey {
	HFSCatalogKey 					hfs;
	HFSPlusCatalogKey 				hfsPlus;
};
typedef union CatalogKey				CatalogKey;
/* Universal catalog data record */

union CatalogRecord {
	SInt16 							recordType;
	HFSCatalogFolder 				hfsFolder;
	HFSCatalogFile 					hfsFile;
	HFSCatalogThread 				hfsThread;
	HFSPlusCatalogFolder 			hfsPlusFolder;
	HFSPlusCatalogFile 				hfsPlusFile;
	HFSPlusCatalogThread 			hfsPlusThread;
};
typedef union CatalogRecord				CatalogRecord;

/*
  	Key for records in the attributes file.  Fields are compared in the order:
  		cnid, attributeName, startBlock
*/

struct AttributeKey {
	UInt16 							keyLength;					/* must set kBTBigKeysMask and kBTVariableIndexKeysMask in BTree header's attributes */
	UInt16 							pad;
	HFSCatalogNodeID 				cnid;						/* file or folder ID */
	UInt32 							startBlock;					/* block # relative to start of attribute */
	UInt16     attrNameLen;     /* number of unicode characters */
	UInt16     attrName[127];   /* attribute name (Unicode) */
};
typedef struct AttributeKey				AttributeKey;
enum {
	kAttributeKeyMaximumLength	= sizeof(AttributeKey) - sizeof(UInt16),
	kAttributeKeyMinimumLength	= kAttributeKeyMaximumLength - 127 * sizeof(UInt16) + sizeof(UInt16)
};

struct HIOParam {
	QElemPtr 						qLink;						/*queue link in header*/
	short 							qType;						/*type byte for safety check*/
	short 							ioTrap;						/*FS: the Trap*/
	Ptr 							ioCmdAddr;					/*FS: address to dispatch to*/
	void* 				ioCompletion;				/*completion routine addr (0 for synch calls)*/
	OSErr 							ioResult;					/*result code*/
	StringPtr 						ioNamePtr;					/*ptr to Vol:FileName string*/
	short 							ioVRefNum;					/*volume refnum (DrvNum for Eject and MountVol)*/
	short 							ioRefNum;
	SInt8 							ioVersNum;
	SInt8 							ioPermssn;
	Ptr 							ioMisc;
	Ptr 							ioBuffer;
	long 							ioReqCount;
	long 							ioActCount;
	short 							ioPosMode;
	long 							ioPosOffset;
};
typedef struct HIOParam HIOParam;

typedef HIOParam *						HIOParamPtr;


struct FCBArray {
	UInt32		length;		/* first word is FCB part length*/
	SFCB		fcb[1];		/* fcb array*/
};
typedef struct FCBArray FCBArray;

/*
	UserCancel callback routine
	
	Input:
			progress:			number from 1 to 100 indicating current progress
			progressChanged:	boolean flag that is true if progress number has been updated
			context:			pointer to context data (if any) that the caller passed to CheckDisk
			
	Output:
			return true if the user wants to cancel the CheckDisk operation
 */

typedef int (*UserCancelProcPtr)(UInt16 progress, UInt16 secondsRemaining, Boolean progressChanged, UInt16 stage, void *context);


#if  0

	//--	User Cancel Proc
	typedef UniversalProcPtr UserCancelUPP;
	
	enum {
		uppUserCancelProcInfo = kPascalStackBased
			 | RESULT_SIZE(kTwoByteCode)
			 | STACK_ROUTINE_PARAMETER(1, kTwoByteCode)
			 | STACK_ROUTINE_PARAMETER(2, kTwoByteCode)
			 | STACK_ROUTINE_PARAMETER(3, kTwoByteCode)
			 | STACK_ROUTINE_PARAMETER(4, kTwoByteCode)
			 | STACK_ROUTINE_PARAMETER(5, kFourByteCode)
	};
	
	#define NewUserCancelProc(userRoutine)		\
			(UserCancelUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppUserCancelProcInfo, GetCurrentArchitecture())
	
	#define CallUserCancelProc(userRoutine, progress, secondsRemaining, progressChanged, stage, context)		\
			CallUniversalProc((UniversalProcPtr)(userRoutine), uppUserCancelProcInfo, (progress), (secondsRemaining), (progressChanged), (stage), (context))

#else /* not CFM */

	typedef UserCancelProcPtr UserCancelUPP;
	
	#define NewUserCancelProc(userRoutine)		\
			((UserCancelUPP) (userRoutine))
	
	#define CallUserCancelProc(userRoutine, progress, secondsRemaining, progressChanged, stage, context)		\
			(*(userRoutine))((progress), (secondsRemaining), (progressChanged), (stage), (context))

#endif


/*
	UserMessage callback routine
	
	Input:
			message:			message from CheckDisk
			messageType:		type of message
			context:			pointer to context data (if any) that the caller passed to CheckDisk
			
	Output:
			return true if the user wants to cancel the CheckDisk operation
 */


typedef pascal void (*UserMessageProcPtr)(StringPtr message, SInt16 messageType, void *context);

#if 0

	//--	User Message Proc
	typedef UniversalProcPtr UserMessageUPP;
	
	enum {
		uppUserMessageProcInfo = kPascalStackBased
			 | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
			 | STACK_ROUTINE_PARAMETER(2, kTwoByteCode)
			 | STACK_ROUTINE_PARAMETER(3, kFourByteCode)
	};
	
	#define NewUserMessageProc(userRoutine)		\
			(UserMessageUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppUserMessageProcInfo, GetCurrentArchitecture())
	
	#define CallUserMessageProc(userRoutine, message, messageType, context)		\
			CallUniversalProc((UniversalProcPtr)(userRoutine), uppUserMessageProcInfo, (message), (messageType), (context))

#else /* not CFM */

	typedef UserMessageProcPtr UserMessageUPP;
	
	#define NewUserMessageProc(userRoutine)		\
			((UserMessageUPP) (userRoutine))
	
	#define CallUserMessageProc(userRoutine, message, messageType, context)		\
			(*(userRoutine))((message), (messageType), (context))

#endif

/* 3843779 Structure to detemine consistency of attribute data and 
 * corresponding bit in catalog record.  Based on Chinese Remainder
 * Theorem
 */
typedef struct PrimeBuckets {
	UInt32	n32[32];
	UInt32	n27[27];
	UInt32	n25[25];
	UInt32	n7[7];
	UInt32	n11[11];
	UInt32	n13[13];
	UInt32	n17[17];
	UInt32	n19[19];
	UInt32	n23[23];
	UInt32	n29[29];
	UInt32	n31[31];
} PrimeBuckets;

/* Record last attribute ID checked, used in CheckAttributeRecord, initialized in ScavSetup */
typedef struct attributeInfo {
	Boolean isValid;
	Boolean hasSecurity;
	int16_t	recordType;
	u_int32_t fileID;
	unsigned char attrname[XATTR_MAXNAMELEN+1];
	u_int32_t totalBlocks;
	u_int32_t calculatedTotalBlocks;
	u_int64_t logicalSize;
} attributeInfo;

/* 	
	VolumeObject encapsulates all infomration about the multiple volume anchor blocks (VHB and MSD) 
	on HFS and HFS+ volumes.  An HFS volume will have two MDBs (primary and alternate HFSMasterDirectoryBlock), 
	a pure HFS+ volume will have two VHBs (primary and alternate HFSPlusVolumeHeader), and a wrapped HFS+ 
	volume will have two MDBs and two VHBs.
*/

/* values for VolumeObject.flags */
enum {
	kVO_Inited			= 0x00000001,	   	// this structured has been initialized
	kVO_PriVHBOK		= 0x00000002,	   	// the primary Volume Header Block is valid
	kVO_AltVHBOK		= 0x00000004,	   	// the alternate Volume Header Block is valid
	kVO_PriMDBOK		= 0x00000008,	   	// the primary Master Directory Block is valid
	kVO_AltMDBOK		= 0x00000010,	   	// the alternate Master Directory Block is valid
};

typedef struct VolumeObject {
	UInt32			flags;
	SVCB * 			vcbPtr;				// pointer to VCB used for this volume
	UInt32			volumeType;			// (kHFSVolumeType or kEmbededHFSPlusVolumeType or kPureHFSPlusVolumeType)
	UInt32			embeddedOffset;		// offset of embedded HFS+ (in bytes) volume into HFS wrapper volume
										//   NOTE - UInt32 is OK since we don't support HFS Wrappers on TB volumes
	UInt32			sectorSize;			// size of a sector for this device
	UInt64			totalDeviceSectors;	// total number of sectors for this volume (from GetDeviceSize)
	UInt64			totalEmbeddedSectors; // total number of sectors for embedded volume
	// location of all possible volume anchor blocks (MDB and VHB) on this volume.  These locations
	// are the sector offset into the volume.  Only wrapped HFS+ volumes use all 4 of these.
	UInt64			primaryVHB;			// not used for HFS volumes
	UInt64			alternateVHB;		// not used for HFS volumes
	UInt64			primaryMDB;			// not used for pure HFS+ volumes
	UInt64			alternateMDB;		// not used for pure HFS+ volumes
} VolumeObject, *VolumeObjectPtr;


typedef struct SGlob {
	SInt16				DrvNum;					//	drive number of target drive
	SInt16				RepLevel;				//	repair level, 1 = minor repair, 2 = major repair
	SInt16				ScavRes;				//	scavenge result code
	OSErr				ErrCode;    			//	error code
	OSErr				IntErr;     			//	internal error code
	UInt16				VIStat;					//	scavenge status flags for volume info 
	UInt16				ABTStat;				//	scavenge status flags for Attributes BTree 
	UInt16				EBTStat;				//	scavenge status flags for extent BTree 
	UInt16				CBTStat;				//	scavenge status flags for catalog BTree 
	UInt16				CatStat;				//	scavenge status flags for catalog file
	UInt16				VeryMinorErrorsStat;	//	scavenge status flags for very minor errors
	UInt16				JStat;					//	scavange status flags for journal errors
	UInt16				PrintStat;				//	info about messages that should be displayed only once
	DrvQElPtr			DrvPtr;					//	pointer to driveQ element for target drive
	UInt32				TarID;					//	target ID (CNID of data structure being verified)
	UInt64				TarBlock;				//	target block/node number being verified
	SInt16				BTLevel;				//	current BTree enumeration level
	SBTPT				*BTPTPtr;				//	BTree path table pointer
	SInt16				DirLevel;				//	current directory enumeration level
	SDPT				*DirPTPtr;				//	directory path table pointer
	SInt16				CNType;					//	current CNode type
	UInt32				ParID;					//	current parent DirID
	CatalogName			CName;					//	current CName
	RepairOrderPtr		MinorRepairsP;			//	ptr to list of problems for later repair
	MissingThread		*missingThreadList;
	Ptr 				FCBAPtr;				//	pointer to scavenger FCB array
	UInt32				**validFilesList;		//	List of valid HFS file IDs

	ExtentsTable		**overlappedExtents;	//	List of overlapped extents
	FileIdentifierTable	**fileIdentifierTable;	//	List of files for post processing

	UInt32				inputFlags;				//	Caller can specify some DFA behaviors

	UInt32				volumeFeatures;			//	bit vector of volume and OS features
	Boolean				usersAreConnected;		//	true if user are connected
	Boolean				fileSharingOn;			//	true if file sharing is on
	UInt32				altBlockLocation;
	Boolean				checkingWrapper;
	SInt16				numExtents;				//	Number of memory resident extents.  3 or 8
	OSErr				volumeErrorCode;
	
	UserCancelUPP		userCancelProc;
	UserMessageUPP		userMessageProc;
	void				*userContext;

	UInt64				onePercent;
	UInt64				itemsToProcess;
	UInt64				itemsProcessed;
	UInt64				lastProgress;
	long				startTicks;
	UInt16				secondsRemaining;

	long				lastTickCount;

	
	SVCB			*calculatedVCB;
	SFCB			*calculatedExtentsFCB;
	SFCB			*calculatedCatalogFCB;
	SFCB			*calculatedAllocationsFCB;
	SFCB			*calculatedAttributesFCB;
	SFCB			*calculatedStartupFCB;
	SFCB			*calculatedRepairFCB;	
	BTreeControlBlock	*calculatedExtentsBTCB;
	BTreeControlBlock	*calculatedCatalogBTCB;
	BTreeControlBlock	*calculatedRepairBTCB;
	BTreeControlBlock	*calculatedAttributesBTCB;

	Boolean			cleanUnmount;
	Boolean			guiControl;
	int				logLevel;
	int				chkLevel;
	int             repairLevel;
	Boolean			minorRepairErrors;	// indicates some minor repairs failed
	int				canWrite;  	// we can safely write to the block device
	int				lostAndFoundMode;  // used when creating lost+found directory
	BTScanState		scanState;

	unsigned char	volumeName[256]; /* volume name in ASCII or UTF-8 */

	PrimeBuckets 	CBTAttrBucket;		/* prime number buckets for Attribute bit in Catalog btree */
	PrimeBuckets 	CBTSecurityBucket;	/* prime number buckets for Security bit in Catalog btree */
	PrimeBuckets 	ABTAttrBucket;		/* prime number buckets for Attribute bit in Attribute btree */
	PrimeBuckets 	ABTSecurityBucket;	/* prime number buckets for Security bit in Attribute btree */
	attributeInfo 	lastAttrInfo; 	/* Record last attribute ID checked, used in CheckAttributeRecord, initialized in ScavSetup */
	UInt16		securityAttrName[XATTR_MAXNAMELEN];	/* Store security attribute name in UTF16, to avoid frequent conversion */
	size_t  	securityAttrLen;
} SGlob, *SGlobPtr;


enum
{
	supportsTrashVolumeCacheFeatureMask		= 1,
	supportsHFSPlusVolsFeatureMask			= 2,
	volumeIsMountedMask						= 4
};

/* scavenger flags */	
	
/* volume info status flags (contents of VIStat) */

#define	S_MDB					0x8000	//	MDB/VHB damaged
#define	S_AltMDB				0x4000	//	Unused	/* alternate MDB damaged */
#define	S_VBM					0x2000	//	volume bit map damaged
#define	S_WMDB					0x1000	//	wrapper MDB is damaged
#define	S_OverlappingExtents	0x0800	//	Overlapping extents found
#define	S_BadMDBdrAlBlSt		0x0400	//	Invalid drAlBlSt field in MDB
#define S_InvalidWrapperExtents	0x0200	//	Invalid catalog extent start in MDB

/* BTree status flags (contents of EBTStat, CBTStat and ABTStat) */

#define	S_BTH					0x8000	/* BTree header damaged */
#define	S_BTM					0x4000	/* BTree map damaged */
#define	S_Indx					0x2000	//	Unused	/* index structure damaged */
#define	S_Leaf					0x1000	//	Unused	/* leaf structure damaged */
#define S_Orphan				0x0800  // orphaned file
#define S_OrphanedExtent		0x0400  // orphaned extent
#define S_ReservedNotZero		0x0200  // the flags or reserved fields are not zero
#define S_RebuildBTree			0x0100  // similar to S_Indx, S_Leaf, but if one is bad we stop checking and the other may also be bad.
#define S_ReservedBTH			0x0080  // fields in the BTree header should be zero but are not
#define S_AttributeCount		0x0040	// incorrect number of xattr in attribute btree in comparison with attribute bit in catalog btree
#define S_SecurityCount			0x0020	// incorrect number of security xattrs in attribute btree in comparison with security bit in catalog btree
#define S_AttrRec				0x0010	// orphaned/unknown record in attribute BTree

/* catalog file status flags (contents of CatStat) */

#define	S_IllName			0x8000	/* illegal name found */
#define	S_Valence			0x4000	/* a directory valence is out of sync */
#define	S_FThd				0x2000	/* dangling file thread records exist */
#define	S_DFCorruption		0x1000	/* disappearing folder corruption detected */
#define	S_NoDir				0x0800	/* missing directory record */
#define S_LockedDirName		0x0400  // locked dir name
#define S_MissingThread		0x0200  /* missing thread record */
#define S_UnlinkedFile		0x0100	/* orphaned link node */
#define S_LinkCount			0x0080	/* data node link count needs repair */
#define S_Permissions		0x0040	/* BSD permissions need repair */
#define S_FileAllocation	0x0020	/* peof or leof needs adjustment */
#define S_BadExtent			0x0010	/* invalid extent */

/* VeryMinorErrorsStat */

#define S_BloatedThreadRecordFound	0x8000  // 2210409, excessivly large thread record found

/* user file status flags (contents of FilStat) */

//#define S_LockedName			0x4000  // locked file name

/* Journal status flag (contents of JStat) */
#define S_BadJournal		0x8000	/* Bad journal content */

/* Print status flag (contents of PrintStat) */
#define S_DamagedDir 		0x8000	/* message for M_LookDamagedDir already printed */
#define S_SymlinkCreate		0x4000	/* message for E_SymlinkCreate already printed */

/*------------------------------------------------------------------------------
 ScavCtrl Interface
------------------------------------------------------------------------------*/

//	Command Codes (commands to ScavControl)
enum
{
	scavInitialize		= 1,			//	Start initial volume check
	scavVerify,							//	Start verify operation
	scavRepair,							//	Start repair opeation
	scavTerminate,						//	Cleanup after scavenge
};


//	Repair Levels
enum
{
	repairLevelNoProblemsFound				= 0,
	repairLevelRepairIfOtherErrorsExist,		//	Bloated thread records, ...
	repairLevelVeryMinorErrors,					//	Missing Custom Icon, Locked Directory name,..., Errors that don't need fixing from CheckDisk (Installer), Non Volume corruption bugs.
	repairLevelVolumeRecoverable,				//	Minor Volume corruption exists
	repairLevelSomeDataLoss,					//	Overlapping extents, some data loss but no scavaging will get it back
	repairLevelWillCauseDataLoss,				//	Missing leaf nodes, repair will lose nodes without scavaging (proceed at your own risk, check disk with other utils)
	repairLevelCatalogBtreeRebuild,				//	Catalog Btree is damaged, repair may lose some data
	repairLevelUnrepairable						//	DFA cannot repair volume
};


/* Status messages written to summary */
enum {
	M_FirstMessage              =  1,

	M_CheckingHFSVolume         =  1,
	M_CheckingHFSPlusVolume     =  2,
	M_ExtBTChk                  =  3,
	M_CatBTChk                  =  4,
	M_CatHChk                   =  5,
	M_AttrBTChk                 =  6,
	M_VolumeBitMapChk           =  7,
	M_VInfoChk                  =  8,
	M_MultiLinkChk              =  9,
	M_Orphaned                  = 10,
	M_RebuildingExtentsBTree    = 11,
	M_RebuildingCatalogBTree    = 12,
	M_RebuildingAttributesBTree = 13,
	M_Repair                    = 14,
	M_NeedsRepair               = 15,
	M_AllOK                     = 16,
	M_RepairOK                  = 17,
	M_RepairFailed              = 18,
	M_CheckFailed               = 19,
	M_Rescan	               	= 20,
	M_Look		               	= 21,
	M_OtherWriters		       	= 22,
	M_CaseSensitive		       	= 23,
	M_ReRepairFailed			= 24,			
	M_LookDamagedDir			= 25,

	M_LastMessage               = 25
};

/*------------------------------------------------------------------------------
 Scavenger Result/Error Codes
------------------------------------------------------------------------------*/

/*
 * Scavenger errors.
 * If negative, they are unrecoverable (scavenging terminates).
 * If positive, they are recoverable (scavenging continues).
 *
 */	
enum {
	E_FirstError		=  500,

	E_PEOF			=  500,	/* Invalid PEOF */
	E_LEOF			=  501,	/* Invalid LEOF */
	E_DirVal		=  502,	/* Invalid directory valence */
	E_CName			=  503,	/* Invalid CName */
	E_NHeight		=  504,	/* Invalid node height */
	E_NoFile		=  505,	/* Missing file record for file thread */
	E_ABlkSz		= -506,	/* Invalid allocation block size */
	E_NABlks		= -507,	/* Invalid number of allocation blocks */
	E_VBMSt			= -508,	/* Invalid VBM start block */
	E_ABlkSt		= -509,	/* Invalid allocation block start */

	E_ExtEnt		= -510,	/* Invalid extent entry */
	E_OvlExt		=  511,	/* overlapped extent allocation */
	E_LenBTH		= -512,	/* Invalid BTH length */
	E_ShortBTM		= -513,	/* BT map too short to repair */
	E_BTRoot		= -514,	/* Invalid root node number */
	E_NType			= -515,	/* Invalid node type */
	E_NRecs			= -516,	/* Invalid record count */
	E_IKey			= -517,	/* Invalid index key */
	E_IndxLk		= -518,	/* Invalid index link */
	E_SibLk			= -519,	/* Invalid sibling link */

	E_BadNode		= -520,	/* Invalid node structure */
	E_OvlNode		= -521,	/* overlapped node allocation */
	E_MapLk			= -522,	/* Invalid map node linkage */
	E_KeyLen		= -523,	/* Invalid key length */
	E_KeyOrd		= -524,	/* Keys out of order */
	E_BadMapN		= -525,	/* Invalid map node */
	E_BadHdrN		= -526,	/* Invalid header node */
	E_BTDepth		= -527,	/* exceeded maximum BTree depth */
	E_CatRec		= -528,	/* Invalid catalog record type */
	E_LenDir		= -529,	/* Invalid directory record length */

	E_LenThd		= -530,	/* Invalid thread record length */
	E_LenFil		= -531,	/* Invalid file record length */
	E_NoRtThd		= -532,	/* Missing thread record for root directory */
	E_NoThd			= -533,	/* Missing thread record */
	E_NoDir			= 534,	/* Missing directory record */
	E_ThdKey		= -535,	/* Invalid key for thread record */
	E_ThdCN			= -536,	/* Invalid  parent CName in thread record */
	E_LenCDR		= -537,	/* Invalid catalog record length */
	E_DirLoop		= -538,	/* loop in directory hierarchy */
	E_RtDirCnt		=  539,	/* Invalid root directory count */

	E_RtFilCnt		=  540,	/* Invalid root file count */
	E_DirCnt		=  541,	/* Invalid volume directory count */
	E_FilCnt		=  542,	/* Invalid volume file count */
	E_CatPEOF		= -543,	/* Invalid catalog PEOF */
	E_ExtPEOF		= -544,	/* Invalid extent file PEOF */
	E_CatDepth		=  545,	/* exceeded maximum catalog depth */
	E_NoFThdFlg		= -546,	/* file thread flag not set in file record */
	E_CatalogFlagsNotZero	=  547,
	E_BadFileName		= -548,	/* Invalid file/folder name problem */
	E_InvalidClumpSize	=  549,	/* bad file clump size */

	E_InvalidBTreeHeader	=  550,	/* Invalid btree header */
	E_LockedDirName		=  551,	/* Inappropriate locked folder name */
	E_EntryNotFound		= -552,	/* volume catalog entry not found */
	E_FreeBlocks		=  553,
	E_MDBDamaged		=  554,	/* MDB Damaged */
	E_VolumeHeaderDamaged	=  555,	/* Volume Header Damaged */
	E_VBMDamaged		=  556,	/* Volume Bit Map needs minor repair */
	E_InvalidNodeSize	= -557,	/* Bad BTree node size */
	E_LeafCnt		=  558,
	E_BadValue		=  559,

	E_InvalidID		=  560,
	E_VolumeHeaderTooNew	=  561,
	E_DiskFull		= -562,
	E_InternalFileOverlap	= -563,	/* This is a serious error */
	E_InvalidVolumeHeader	= -564,
	E_InvalidMDBdrAlBlSt	=  565,
	E_InvalidWrapperExtents	=  566,
	E_InvalidLinkCount	=  567,	/* Invalid Hardlink count */
	E_UnlinkedFile		=  568,	/* Unlinked file needs to be deleted */
	E_InvalidPermissions	=  569,

	E_InvalidUID		=  570,
	E_IllegalName		=  571,
	E_IncorrectNumThdRcd	=  572,
	E_SymlinkCreate		=  573,
	E_IncorrectAttrCount	=  574,	/* Incorrect attributes in attr btree with attr bits in catalog btree */
	E_IncorrectSecurityCount=  575, /* Incorrect security attributes in attr btree with security bits in catalog btree */
	E_PEOAttr		=  576, /* Incorrect physical end of extended attribute data */
	E_LEOAttr		=  577, /* Incorrect logical end of extended attribute data */
	E_AttrRec		=  578, /* Invalid attribute record (overflow extent without original extent, unknown type) */

	E_LastError		=  578
};


/* Internal DFA error codes */
enum {
	errRebuildBtree				= -1001		/* BTree requires rebuilding. */
};


enum {																/*	extendFileContigMask		= 0x0002*/
	kEFContigBit				= 1,							/*	force contiguous allocation*/
	kEFContigMask				= 0x02,
	kEFAllBit					= 0,							/*	allocate all requested bytes or none*/
	kEFAllMask					= 0x01,
	kEFNoClumpBit				= 2,							/*	Don't round up requested size to multiple of clump size*/
	kEFNoClumpMask				= 0x04,							/*	TruncateFile option flags*/
	kTFTrunExtBit				= 0,							/*	truncate to the extent containing new PEOF*/
	kTFTrunExtMask				= 1
};



// Encoding vs. Index
//
// For runtime table lookups and for the volume encoding bitmap we
// need to map some encodings to keep them in a reasonable range.
//

enum {
	kTextEncodingMacRoman		= 0L,
	kTextEncodingMacFarsi		= 0x8C,	 /* Like MacArabic but uses Farsi digits*/
																/* The following use script code 7, smCyrillic*/
	kTextEncodingMacUkrainian	= 0x98,	/* The following use script code 32, smUnimplemented*/

	kIndexMacUkrainian	= 48,		// MacUkrainian encoding is 152
	kIndexMacFarsi		= 49		// MacFarsi encoding is 140
};

#define MapEncodingToIndex(e) \
	( (e) < 48 ? (e) : ( (e) == kTextEncodingMacUkrainian ? kIndexMacUkrainian : ( (e) == kTextEncodingMacFarsi ? kIndexMacFarsi : kTextEncodingMacRoman) ) )

#define MapIndexToEncoding(i) \
	( (i) == kIndexMacFarsi ? kTextEncodingMacFarsi : ( (i) == kIndexMacUkrainian ? kTextEncodingMacUkrainian : (i) ) )

#define ValidMacEncoding(e)	\
	( ((e) < 39)  ||  ((e) == kTextEncodingMacFarsi)  ||  ((e) == kTextEncodingMacUkrainian) )




extern	void	WriteMsg( SGlobPtr GPtr, short messageID, short messageType );
extern	void	WriteError( SGlobPtr GPtr, short msgID, UInt32 tarID, UInt64 tarBlock );
extern	short	CheckPause( void );

extern void	PrintError(SGlobPtr GPtr, short error, int vargc, ...);
extern void	PrintStatus(SGlobPtr GPtr, short status, int vargc, ...);


/* ------------------------------- From SControl.c ------------------------------- */

void			ScavCtrl( SGlobPtr GPtr, UInt32 ScavOp, short *ScavRes );

extern	short	CheckForStop( SGlobPtr GPtr );
	

/* ------------------------------- From SRepair.c -------------------------------- */

extern	OSErr	RepairVolume( SGlobPtr GPtr );

extern	int		FixDFCorruption( const SGlobPtr GPtr, RepairOrderPtr DFOrderP );

extern	OSErr	ProcessFileExtents( SGlobPtr GPtr, SFCB *fcb, UInt8 forkType, UInt16 flags, Boolean isExtentsBTree, Boolean *hasOverflowExtents, UInt32 *blocksUsed  );

/* Function to get return file path/name given an ID */
extern 	OSErr 	GetSystemFileName(UInt32 fileID, char *filename, unsigned int *filenamelen);
extern 	OSErr 	GetFileNamePathByID(SGlobPtr GPtr, UInt32 fileID, char *fullPath, unsigned int *fullPathLen, char *fileName, unsigned int *fileNameLen, u_int16_t *status);
#define FNAME_BUF2SMALL	0x001	/* filename buffer was too small */
#define FNAME_BIGNAME	0x002	/* filename is greater than NAME_MAX bytes */
#define FPATH_BUF2SMALL	0x010	/* path buffer was too small */
#define	FPATH_BIGNAME	0x020	/* intermediate component in path is greater than NAME_MAX bytes */
#define	F_RESERVE_FILEID 0x100	/* file ID was less than kHFSFirstUserCatalogNodeID */

/* ------------------------------- From SUtils.c --------------------------------- */

extern	int		AllocBTN( SGlobPtr GPtr, short FilRefN, UInt32 NodeNum );

extern	int		IntError( SGlobPtr GPtr, OSErr ErrCode );

extern	void	RcdError( SGlobPtr GPtr, OSErr ErrCode );

extern	RepairOrderPtr AllocMinorRepairOrder( SGlobPtr GPtr, int extraBytes );

extern	void	SetDFAStage( UInt32 stage );
extern	UInt32	GetDFAGlobals( void );

extern void		InitializeVolumeObject( SGlobPtr GPtr );
extern void 	CheckEmbeddedVolInfoInMDBs( SGlobPtr GPtr );
extern VolumeObjectPtr  GetVolumeObjectPtr( void );
extern OSErr	GetVolumeObjectVHB( BlockDescriptor * theBlockDescPtr );
extern void 	GetVolumeObjectBlockNum( UInt64 * theBlockNumPtr );
extern OSErr 	GetVolumeObjectAlternateBlock( BlockDescriptor * theBlockDescPtr );
extern OSErr 	GetVolumeObjectPrimaryBlock( BlockDescriptor * theBlockDescPtr );
extern void 	GetVolumeObjectAlternateBlockNum( UInt64 * theBlockNumPtr );
extern void 	GetVolumeObjectPrimaryBlockNum( UInt64 * theBlockNumPtr );
extern OSErr	GetVolumeObjectAlternateMDB( BlockDescriptor * theBlockDescPtr );
extern OSErr 	GetVolumeObjectPrimaryMDB( BlockDescriptor * theBlockDescPtr );
extern OSErr 	GetVolumeObjectVHBorMDB( BlockDescriptor * theBlockDescPtr );
extern void 	PrintName( int theCount, const UInt8 *theNamePtr, Boolean isUnicodeString );
extern void 	PrintVolumeObject( void );
extern Boolean 	VolumeObjectIsValid( void );
extern Boolean 	VolumeObjectIsHFSPlus( void );
extern Boolean 	VolumeObjectIsHFS( void );
extern Boolean 	VolumeObjectIsEmbeddedHFSPlus( void );
extern Boolean 	VolumeObjectIsPureHFSPlus( void );
extern void 	RecordXAttrBits(SGlobPtr GPtr, UInt16 flags, HFSCatalogNodeID fileid, UInt16 btreetype); 
extern int ComparePrimeBuckets(SGlobPtr GPtr, UInt16 BitMask); 

extern	void	InvalidateCalculatedVolumeBitMap( SGlobPtr GPtr );

extern	OSErr	GetVolumeFeatures( SGlobPtr GPtr );

OSErr	FlushAlternateVolumeControlBlock( SVCB *vcb, Boolean isHFSPlus );

extern	void	ConvertToHFSPlusExtent(const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents);


/* ------------------------------- From CatalogCheck.c -------------------------------- */

extern	OSErr	CheckCatalogBTree( SGlobPtr GPtr );	//	catalog btree check

extern int  RecordBadAllocation(UInt32 parID, unsigned char * filename, UInt32 forkType, UInt32 oldBlkCnt, UInt32 newBlkCnt);

extern int  RecordTruncation(UInt32 parID, unsigned char * filename, UInt32 forkType, UInt64 oldSize,  UInt64 newSize);

/* ------------------------------- From SVerify1.c -------------------------------- */

extern	OSErr	CatFlChk( SGlobPtr GPtr );		//	catalog file check
	
extern	OSErr	CatHChk( SGlobPtr GPtr );		//	catalog hierarchy check

extern	OSErr	ExtBTChk( SGlobPtr GPtr );		//	extent btree check

extern	OSErr	BadBlockFileExtentCheck( SGlobPtr GPtr );	//	bad block file extent check

extern	OSErr	AttrBTChk( SGlobPtr GPtr );		//	attributes btree check

extern	OSErr	IVChk( SGlobPtr GPtr );

extern	int	CheckForClean( SGlobPtr GPtr, Boolean markClean );

extern  int	CheckIfJournaled(SGlobPtr GPtr);

extern	OSErr	VInfoChk( SGlobPtr GPtr );

extern	OSErr	VLockedChk( SGlobPtr GPtr );

extern	void	BuildExtentKey( Boolean isHFSPlus, UInt8 forkType, HFSCatalogNodeID fileNumber, UInt32 blockNumber, void * key );

extern	OSErr	OrphanedFileCheck( SGlobPtr GPtr, Boolean *problemsFound );

extern	int		cmpLongs (const void *a, const void *b);

extern  int CheckAttributeRecord(SGlobPtr GPtr, const HFSPlusAttrKey *key, const HFSPlusAttrRecord *rec, UInt16 reclen);

extern  int FindOrigOverlapFiles(SGlobPtr GPtr);

extern  void PrintOverlapFiles (SGlobPtr GPtr);

/* ------------------------------- From SVerify2.c -------------------------------- */

typedef int (* CheckLeafRecordProcPtr)(SGlobPtr GPtr, void *key, void *record, UInt16 recordLen);

extern	int  BTCheck(SGlobPtr GPtr, short refNum, CheckLeafRecordProcPtr checkLeafRecord);

extern	int		BTMapChk( SGlobPtr GPtr, short FilRefN );

extern	OSErr	ChkCName( SGlobPtr GPtr, const CatalogName *name, Boolean unicode );	//	check catalog name

extern	OSErr	CmpBTH( SGlobPtr GPtr, SInt16 fileRefNum );

extern	int		CmpBTM( SGlobPtr GPtr, short FilRefN );

extern	int		CmpMDB( SGlobPtr GPtr, HFSMasterDirectoryBlock * mdbP);

extern	int		CmpVBM( SGlobPtr GPtr );

extern	OSErr	CmpBlock( void *block1P, void *block2P, UInt32 length ); /* same as 'memcmp', but EQ/NEQ only */
	
extern	OSErr	ChkExtRec ( SGlobPtr GPtr, const void *extents , unsigned int *lastExtentIndex);


/* -------------------------- From SRebuildCatalogBTree.c ------------------------- */

extern	OSErr 	RebuildCatalogBTree( SGlobPtr theSGlobPtr );


/* -------------------------- From SCatalog.c ------------------------- */

extern OSErr	UpdateFolderCount( 	SVCB *vcb, 
									HFSCatalogNodeID pid, 
									const CatalogName *name, 
									SInt16 newType,
									UInt32 hint, 
									SInt16 valenceDelta );

/* ------------------------------- From SExtents.c -------------------------------- */
OSErr	ZeroFileBlocks( SVCB *vcb, SFCB *fcb, UInt32 startingSector, UInt32 numberOfSectors );

OSErr MapFileBlockC (
	SVCB		*vcb,				// volume that file resides on
	SFCB			*fcb,				// FCB of file
	UInt32			numberOfBytes,		// number of contiguous bytes desired
	UInt32			sectorOffset,		// starting offset within file (in 512-byte sectors)
	UInt64			*startSector,		// first 512-byte volume sector (NOT an allocation block)
	UInt32			*availableBytes);	// number of contiguous bytes (up to numberOfBytes)

OSErr DeallocateFile(SVCB *vcb, CatalogRecord * fileRec);

OSErr ExtendFileC (
	SVCB		*vcb,				// volume that file resides on
	SFCB			*fcb,				// FCB of file to truncate
	UInt32			sectorsToAdd,		// number of sectors to allocate
	UInt32			flags,				// EFContig and/or EFAll
	UInt32			*actualSectorsAdded); // number of bytes actually allocated
	
OSErr FlushExtentFile( SVCB *vcb );

void ExtDataRecToExtents(
	const HFSExtentRecord	oldExtents,
	HFSPlusExtentRecord	newExtents);

OSErr UpdateExtentRecord (
	const SVCB		*vcb,
	SFCB					*fcb,
	const HFSPlusExtentKey	*extentFileKey,
	HFSPlusExtentRecord		extentData,
	UInt32					extentBTreeHint);

OSErr	CheckFileExtents( SGlobPtr GPtr, UInt32 fileNumber, UInt8 forkType, const unsigned char *xattrName,
                          const void *extents, UInt32 *blocksUsed );
OSErr	GetBTreeHeader( SGlobPtr GPtr, SFCB* fcb, BTHeaderRec *header );
OSErr	CompareVolumeBitMap( SGlobPtr GPtr, SInt32 whichBuffer );
OSErr	CompareVolumeHeader( SGlobPtr GPtr, HFSPlusVolumeHeader *vh );
OSErr	CreateExtentsBTreeControlBlock( SGlobPtr GPtr );
OSErr	CreateCatalogBTreeControlBlock( SGlobPtr GPtr );
OSErr	CreateAttributesBTreeControlBlock( SGlobPtr GPtr );
OSErr	CreateExtendedAllocationsFCB( SGlobPtr GPtr );


OSErr	CacheWriteInPlace( SVCB *vcb, UInt32 fileRefNum,  HIOParam *iopb, UInt64 currentPosition,
	UInt32 maximumBytes, UInt32 *actualBytes );


/* Generic B-tree call back routines */
OSStatus GetBlockProc (SFCB *filePtr, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block);
OSStatus ReleaseBlockProc (SFCB *filePtr, BlockDescPtr blockPtr, ReleaseBlockOptions options);
OSStatus SetEndOfForkProc (SFCB *filePtr, FSSize minEOF, FSSize maxEOF);
OSStatus SetBlockSizeProc (SFCB *filePtr, ByteCount blockSize, ItemCount minBlockCount);

void DFA_PrepareInputName(ConstStr31Param name, Boolean isHFSPlus, CatalogName *catalogName);

extern	UInt32	CatalogNameSize( const CatalogName *name, Boolean isHFSPlus);

void	SetupFCB( SVCB *vcb, SInt16 refNum, UInt32 fileID, UInt32 fileClumpSize );


extern	void	CalculateItemCount( SGlob *GPtr, UInt64 *itemCount, UInt64 *onePercent );



//	Macros
extern		BTreeControlBlock*	GetBTreeControlBlock( short refNum );
#define		GetBTreeControlBlock(refNum)	((BTreeControlBlock*) ResolveFCB((refNum))->fcbBtree)

/*	The following macro marks a VCB as dirty by setting the upper 8 bits of the flags*/
EXTERN_API_C( void )
MarkVCBDirty					(SVCB *			vcb);

#define	MarkVCBDirty(vcb)	((void) (vcb->vcbFlags |= 0xFF00))
EXTERN_API_C( void )
MarkVCBClean					(SVCB *			vcb);

#define	MarkVCBClean(vcb)	((void) (vcb->vcbFlags &= 0x00FF))
EXTERN_API_C( Boolean )
IsVCBDirty						(SVCB *			vcb);

#define	IsVCBDirty(vcb)		((Boolean) ((vcb->vcbFlags & 0xFF00) != 0))


extern	pascal void M_Debugger(void);
extern	pascal void M_DebugStr(ConstStr255Param debuggerMsg);
#if ( DEBUG_BUILD )
	#define	M_Debuger()					Debugger()
	#define	M_DebugStr( debuggerMsg )	DebugStr( debuggerMsg )
#else
	#define	M_Debuger()
	#define	M_DebugStr( debuggerMsg )
#endif


/*	Test for error and return if error occurred*/
EXTERN_API_C( void )
ReturnIfError					(OSErr 					result);

#define	ReturnIfError(result)					if ( (result) != noErr ) return (result); else ;
/*	Test for passed condition and return if true*/
EXTERN_API_C( void )
ReturnErrorIf					(Boolean 				condition,
								 OSErr 					result);

#define	ReturnErrorIf(condition, error)			if ( (condition) )	return( (error) );
/*	Exit function on error*/
EXTERN_API_C( void )
ExitOnError						(OSErr 					result);

#define	ExitOnError( result )					if ( ( result ) != noErr )	goto ErrorExit; else ;

/*	Return the low 16 bits of a 32 bit value, pinned if too large*/
EXTERN_API_C( UInt16 )
LongToShort						(UInt32 				l);

#define	LongToShort( l )	l <= (UInt32)0x0000FFFF ? ((UInt16) l) : ((UInt16) 0xFFFF)


EXTERN_API_C( UInt32 )
GetDFAStage						(void);

EXTERN_API_C(OSErr)
DeleteCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint);

EXTERN_API_C(OSErr)
GetCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint, CatalogRecord *data);

EXTERN_API_C( SInt32 )
CompareCatalogKeys				(HFSCatalogKey *		searchKey,
								 HFSCatalogKey *		trialKey);

EXTERN_API_C( SInt32 )
CompareExtendedCatalogKeys		(HFSPlusCatalogKey *	searchKey,
								 HFSPlusCatalogKey *	trialKey);
EXTERN_API_C( SInt32 )
CaseSensitiveCatalogKeyCompare (HFSPlusCatalogKey * searchKey,
                                HFSPlusCatalogKey * trialKey);

EXTERN_API_C( SInt32 )
CompareExtentKeys				(const HFSExtentKey *	searchKey,
								 const HFSExtentKey *	trialKey);

EXTERN_API_C( SInt32 )
CompareExtentKeysPlus			(const HFSPlusExtentKey * searchKey,
								 const HFSPlusExtentKey * trialKey);
EXTERN_API_C( SInt32 )
CompareAttributeKeys			(const AttributeKey * searchKey,  const AttributeKey * trialKey);
EXTERN_API( SFCB* )
ResolveFCB						(short 					fileRefNum);

EXTERN_API_C( OSErr )
ValidVolumeHeader				(HFSPlusVolumeHeader *	volumeHeader);


/* Old B-tree Manager API (going away soon!) */

EXTERN_API_C( OSErr )
SearchBTreeRecord				(SFCB 				*fcb,
								 const void *			key,
								 UInt32 				hint,
								 void *					foundKey,
								 void *					data,
								 UInt16 *				dataSize,
								 UInt32 *				newHint);

EXTERN_API_C( OSErr )
GetBTreeRecord					(SFCB 				*fcb,
								 SInt16 				selectionIndex,
								 void *					key,
								 void *					data,
								 UInt16 *				dataSize,
								 UInt32 *				newHint);

EXTERN_API_C( OSErr )
InsertBTreeRecord				(SFCB 				*fcb,
								 const void *			key,
								 const void *			data,
								 UInt16 				dataSize,
								 UInt32 *				newHint);

EXTERN_API_C( OSErr )
DeleteBTreeRecord				(SFCB 				*fcb,
								 const void *			key);

EXTERN_API_C( OSErr )
ReplaceBTreeRecord				(SFCB 				*fcb,
								 const void *			key,
								 UInt32 				hint,
								 void *					newData,
								 UInt16 				dataSize,
								 UInt32 *				newHint);

EXTERN_API_C( void )
InitBTreeHeader					(UInt32 				fileSize,
								 UInt32 				clumpSize,
								 UInt16 				nodeSize,
								 UInt16 				recordCount,
								 UInt16 				keySize,
								 UInt32 				attributes,
								 UInt32 *				mapNodes,
								 void *					buffer);

EXTERN_API_C( OSErr )
UpdateFreeCount					(SVCB *			vcb);


EXTERN_API_C(Boolean)
NodesAreContiguous(	SFCB		*fcb,
			UInt32		nodeSize);



UInt32 GetTimeUTC(void);
UInt32 GetTimeLocal(Boolean forHFS);

OSErr FlushVolumeControlBlock( SVCB *vcb );

pascal short ResolveFileRefNum(SFCB * fileCtrlBlockPtr);

extern UInt32	CatalogNameLength( const CatalogName *name, Boolean isHFSPlus);

extern void		CopyCatalogName( const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus);

extern	void	UpdateCatalogName( ConstStr31Param srcName, Str31 destName);

extern	void	BuildCatalogKey( HFSCatalogNodeID parentID, const CatalogName *name, Boolean isHFSPlus,
								 CatalogKey *key);

extern void		UpdateVolumeEncodings( SVCB *volume, TextEncoding encoding);


OSErr BlockAllocate (SVCB *vcb, UInt32 startingBlock, UInt32 blocksRequested, UInt32 blocksMaximum,
			Boolean forceContiguous, UInt32 *actualStartBlock, UInt32 *actualNumBlocks);
OSErr	BlockDeallocate ( SVCB *vcb, UInt32 firstBlock, UInt32 numBlocks);
UInt32	DivideAndRoundUp( UInt32 numerator, UInt32 denominator);

OSErr InitializeBlockCache ( UInt32 blockSize, UInt32 blockCount );

void	SetFCBSPtr( Ptr value );
Ptr	GetFCBSPtr( void );


/* 
 * UTF-8 conversion routines
 */
extern int utf_decodestr(const unsigned char *, size_t, u_int16_t *, size_t *);
extern int utf_encodestr(const u_int16_t *, size_t, unsigned char *, size_t *);

/* 
 * HardLink checking routines
 */
extern int   HardLinkCheckBegin(SGlobPtr gp, void** cookie);
extern void  HardLinkCheckEnd(void * cookie);
extern void  CaptureHardLink(void * cookie, UInt32 linkID);
extern int   CheckHardLinks(void *cookie);

/*
 * Volume Bitmap checking routines
 */
extern int  BitMapCheckBegin(SGlobPtr g);
extern int  BitMapCheckEnd(void);
extern int  CaptureBitmapBits(UInt32 startBit, UInt32 bitCount);
extern int  ReleaseBitmapBits(UInt32 startBit, UInt32 bitCount);
extern int  CheckVolumeBitMap(SGlobPtr g, Boolean repair);
extern void UpdateFreeBlockCount(SGlobPtr g);
extern int 	AllocateContigBitmapBits (SVCB *vcb, UInt32 numBlocks, UInt32 *actualStartBlock);

#ifdef __cplusplus
};
#endif

#endif /* __SCAVENGER__ */