1/*
2 * Copyright (c) 1999-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/* Scavenger.h */
24
25#ifndef __SCAVENGER__
26#define __SCAVENGER__
27
28#define pascal
29
30#include "SRuntime.h"
31#include "BTree.h"
32#include "BTreePrivate.h"
33#include "CheckHFS.h"
34#include "BTreeScanner.h"
35#include "hfs_endian.h"
36#include "../fsck_debug.h"
37#include "../fsck_messages.h"
38#include "../fsck_hfs_msgnums.h"
39#include "../fsck_msgnums.h"
40#include "../fsck_hfs.h"
41
42#include <assert.h>
43#include <sys/xattr.h>
44#include <sys/acl.h>
45#include <sys/kauth.h>
46#include <sys/errno.h>
47#include <sys/syslimits.h>
48#include <sys/param.h>
49#include <sys/sysctl.h>
50#include <sys/mount.h>
51#include <hfs/hfs_mount.h>
52
53#ifdef __cplusplus
54extern	"C" {
55#endif
56
57
58#define kFSCKMountVersion	0x6673636B	/* 'fsck' made changes */
59
60enum {
61	Log2BlkLo				= 9,					// number of left shifts to convert bytes to block.lo
62	Log2BlkHi				= 23					// number of right shifts to convert bytes to block.hi
63};
64
65enum {
66	kNoHint						= 0
67};
68
69
70//
71// Misc constants
72//
73
74/* IO size for reading or writing disk blocks */
75#define DISK_IOSIZE	32768
76
77#define kMaxReScan	3	/* max times to re-scan volume on repair success */
78
79#define	kBTreeHeaderUserBytes	128
80
81#define	kBusErrorValue	0x50FF8001
82
83//�� Danger! This should not be hard coded
84#define	kMaxClumpSize	0x100000	/* max clump size is 1MB (2048 btree nodes) */
85
86#define	MDB_FNum	1				/* file number representing the MDB */
87#define	AMDB_FNum	-1				/* file number representing the alternate MDB */
88#define	VBM_FNum	2				/* file number representing the volume bit map */
89#define	MDB_BlkN	2				/* logical block number for the MDB */
90
91#define kCalculatedExtentRefNum			( 0 )
92#define kCalculatedCatalogRefNum		( 1*sizeof(SFCB) )
93#define kCalculatedAllocationsRefNum	( 2*sizeof(SFCB) )
94#define kCalculatedAttributesRefNum		( 3*sizeof(SFCB) )
95#define kCalculatedStartupRefNum		( 4*sizeof(SFCB) )
96#define kCalculatedRepairRefNum			( 5*sizeof(SFCB) )
97
98#define	Max_ABSiz	0x7FFFFE00		/* max allocation block size (multiple of 512 */
99#define	Blk_Size	512				/* size of a logical block */
100#define kHFSBlockSize 512			/* HFS block size */
101
102// only the lower 7 bits are considered to be invalid, all others are valid -djb
103#define	VAtrb_Msk	0x007F			/* volume attribute mask - invalid bits */
104#define	VAtrb_DFlt	0x0100			/* default volume attribute flags */
105#define	VAtrb_Cons	0x0100			/* volume consistency flag */
106#define kHFSCatalogNodeIDsReused 0x1000
107
108
109/*
110 *	File type and creator for TextEdit documents
111 */
112enum {
113	kTextFileType		= 0x54455854,	/* 'TEXT' */
114	kTextFileCreator	= 0x74747874,	/* 'ttxt' */
115};
116
117/*
118 *	Alias type and creator for directory hard links
119 */
120enum {
121	kHFSAliasType		= 0x66647270, 	/* 'fdrp' */
122	kHFSAliasCreator	= 0x4D414353	/* 'MACS' */
123};
124
125/*------------------------------------------------------------------------------
126 BTree data structures
127------------------------------------------------------------------------------*/
128
129/* misc BTree constants */
130
131#define	BTMaxDepth	8				/* max tree depth */
132#define	Num_HRecs	3				/* number of records in BTree Header node */
133#define	Num_MRecs	1				/* number of records in BTree Map node */
134
135
136
137//	DFA extensions to the HFS/HFS+ BTreeControlBlock
138typedef struct BTreeExtensionsRec
139{
140	Ptr 				BTCBMPtr;			//	pointer to scavenger BTree bit map
141	UInt32				BTCBMSize;			//	size of the bitmap, bytes
142	BTreeControlBlock	*altBTCB;			//	BTCB DFA builds up
143	UInt32				realFreeNodeCount;	//	Number of real free nodes, taken from disk, for more accurate progress information
144} BTreeExtensionsRec;
145
146
147
148/*
149 * Scavenger BTree Path Record (STPR)
150 */
151typedef struct STPR {
152	UInt32			TPRNodeN;		/* node number */
153	SInt16			TPRRIndx;		/* record index */
154	SInt16			unused;			/* not used - makes debugging easier */
155	UInt32			TPRLtSib;		/* node number of left sibling node */
156	UInt32			TPRRtSib;		/* node number of right sibling node */
157	} STPR, *STPRPtr;
158
159typedef	STPR SBTPT[BTMaxDepth]; 		/* BTree path table */
160
161#define	LenSBTPT	( sizeof(STPR) * BTMaxDepth )	/* length of BTree Path Table */
162
163
164
165
166/*------------------------------------------------------------------------------
167 CM (Catalog Manager) data structures
168 ------------------------------------------------------------------------------*/
169
170//
171//	Misc constants
172//
173#define CMMaxDepth	100				/* max catalog depth (Same as Finder 7.0) */
174
175#define fNameLocked 4096
176
177union CatalogName {
178	Str31 							pstr;
179	HFSUniStr255 					ustr;
180};
181typedef union CatalogName				CatalogName;
182
183//
184//	Scavenger Directory Path Record (SDPR)
185//
186typedef struct SDPR {
187	UInt32				directoryID;		//	directory ID
188	UInt32				offspringIndex;		//	offspring index
189	UInt32				directoryHint;		//	BTree hint for directory record
190	long				threadHint;			//	BTree hint for thread record
191	HFSCatalogNodeID	parentDirID;		//	parent directory ID
192	CatalogName			directoryName;		//	directory CName
193} SDPR;
194
195enum {
196//	kInvalidMRUCacheKey			= -1L,							/* flag to denote current MRU cache key is invalid*/
197	kDefaultNumMRUCacheBlocks	= 16							/* default number of blocks in each cache*/
198};
199
200
201/*
202 * UTCacheReadIP and UTCacheWriteIP cacheOption
203 */
204
205enum {
206	noCacheBit   = 5,	/* don't cache this please */
207	noCacheMask  = 0x0020,
208	rdVerifyBit  = 6,	/* read verify */
209	rdVerifyMask = 0x0040
210};
211
212
213/*------------------------------------------------------------------------------
214 Low-level File System Error codes
215------------------------------------------------------------------------------*/
216
217/* The DCE bits are defined as follows (for the word of flags): */
218
219enum
220{
221	Is_AppleTalk		= 0,
222	Is_Agent			= 1,			// future use
223	FollowsNewRules		= 2,			// New DRVR Rules Bit
224	Is_Open				= 5,
225	Is_Ram_Based		= 6,
226	Is_Active			= 7,
227	Read_Enable			= 8,
228	Write_Enable		= 9,
229	Control_Enable		= 10,
230	Status_Enable		= 11,
231	Needs_Goodbye		= 12,
232	Needs_Time			= 13,
233	Needs_Lock			= 14,
234
235	Is_AppleTalk_Mask	= 1 << Is_AppleTalk,
236	Is_Agent_Mask		= 1 << Is_Agent,
237	FollowsRules_Mask	= 1 << FollowsNewRules,
238	Is_Open_Mask		= 1 << Is_Open,
239	Is_Ram_Based_Mask	= 1 << Is_Ram_Based,
240	Is_Active_Mask		= 1 << Is_Active,
241	Read_Enable_Mask	= 1 << Read_Enable,
242	Write_Enable_Mask	= 1 << Write_Enable,
243	Control_Enable_Mask	= 1 << Control_Enable,
244	Status_Enable_Mask	= 1 << Status_Enable,
245	Needs_Goodbye_Mask	= 1 << Needs_Goodbye,
246	Needs_Time_Mask		= 1 << Needs_Time,
247	Needs_Lock_Mask		= 1 << Needs_Lock
248};
249
250enum {
251	cdInternalErr					= -1312,		//	internal CheckDisk error
252	cdVolumeNotFoundErr				= -1313,		//	cound not find volume (could be offline)
253	cdCannotReadErr					= -1314,		//	unable to read from disk
254	cdCannotWriteErr				= -1315,		//	unable to write to disk
255	cdNotHFSVolumeErr				= -1316,		//	not an HFS disk
256	cdUnrepairableErr				= -1317,		//	volume needs major repairs that CheckDisk cannot fix
257	cdRepairFailedErr				= -1318,		//	repair failed
258	cdUserCanceledErr				= -1319,		//	user interrupt
259	cdVolumeInUseErr				= -1320,		//	volume modifed by another app
260	cdNeedsRepairsErr				= -1321,		//	volume needs repairs (see repairInfo for additional info)
261	cdReMountErr					= -1322,		//	Cannot remount volume
262	cdUnknownProcessesErr			= -1323,		//	Volume cannot be unmounted and unknown processes are running
263	cdDamagedWrapperErr				= -1324,		//	HFS Wrapper damaged error.
264	cdIncompatibleOSErr				= -1325,		//	Current OS version is incompatible
265	cdMemoryFullErr					= -1326			//	not enough memory to check disk
266};
267
268
269enum {
270	fsDSIntErr	= -127	/* non-hardware Internal file system error */
271};
272
273//	Repair Info - additional info returned when a repair is attempted
274enum {
275	kFileSharingEnabled		= 0x00000001,
276	kDiskIsLocked			= 0x00000002,
277	kDiskIsBoot			= 0x00000004,
278	kDiskHasOpenFiles		= 0x00000008,
279	kVolumeHadOverlappingExtents	= 0x00000010,	// repairLevelSomeDataLoss
280	kVolumeClean			= 0x00000020,
281
282	kRepairsWereMade		= 0x80000000
283};
284
285//	Input parameters to CheckDisk
286enum
287{
288	ignoreRunningProcessesMask		= 0x00000001,	//	Assumes caller has shut down processes
289	checkDiskVersionMask			= 0x00000004	//	Will just return back the version in repairInfo.
290};
291
292//	Message types, so the user can treat and display accordingly
293enum {
294	kStatusMessage					= 0x0000,
295	kTitleMessage					= 0x0001,
296	kErrorMessage					= 0x0002
297};
298
299//	<10> Current stage of CheckDisk passed to cancel proc.
300//	File System is marked busy during kRepairStage, so WaitNextEvent and I/O cannot be done during this stage.
301
302enum {
303	kHFSStage						= 0,
304	kRepairStage,
305	kVerifyStage,
306	kAboutToRepairStage
307};
308
309//	Resource ID of 'STR ' resource containing the name of of the folder to create aliases to damaged files.
310enum {
311	rDamagedFilesDirSTRid			= -20886
312};
313
314//	Type of volume
315enum {
316	kUnknownVolumeType 	= 0,
317	kHFSVolumeType,
318	kEmbededHFSPlusVolumeType,
319	kPureHFSPlusVolumeType
320};
321
322
323enum {
324	kStatusLines	= 131,
325	kFirstError		= 500,
326
327	kHighLevelInfo	= 1100,
328	kBasicInfo		= 1200,
329	kErrorInfo		= 1202,
330
331	kErrorBase		= -1310
332};
333
334
335/*------------------------------------------------------------------------------
336 Minor Repair Interface (records compiled during scavenge, later repaired)
337 Note that not all repair types use all of these fields.
338 -----------------------------------------------------------------------------*/
339
340 typedef struct	RepairOrder			/* a node describing a needed minor repair */
341 {
342 	struct RepairOrder	*link;	/* link to next node, or NULL */
343	SInt16			type;	/* type of error, as an error code (E_DirVal etc) */
344	SInt16		forkType;	/* which file fork */
345	UInt64		correct;	/* correct valence */
346	UInt64		incorrect;	/* valence as found in volume (for consistency chk) */
347	UInt32		maskBit;	/* incorrect bit */
348	UInt32		hint;		/* B-tree node hint */
349	UInt32		parid;		/* parent ID */
350	unsigned char name[1];	/* dir or file name */
351 } RepairOrder, *RepairOrderPtr;
352
353
354 typedef struct	EmbededVolDescription
355 {
356 	SInt16				drAlBlSt;
357	UInt16 				drEmbedSigWord;
358 	HFSExtentDescriptor	drEmbedExtent;
359 } EmbededVolDescription;
360
361
362// define the correct drive queue structure
363typedef struct ExtendedDrvQueue
364{
365	char dQVolumeLocked;
366	char dQDiskInDrive;
367	char dQUsedInternally;
368	char dQDiskIsSingleSided;
369	QElemPtr qLink;
370	short qType;
371	short dQDrive;
372	short dQRefNum;
373	short dQFSID;
374	short dQDrvSz;
375	short dQDrvSz2;
376}ExtendedDrvQueue;
377
378
379/*------------------------------------------------------------------------------
380 Scavenger Global Area - (SGlob)
381------------------------------------------------------------------------------*/
382typedef struct MissingThread
383{
384	struct MissingThread  *link;		/* link to next node, or NULL */
385	UInt32                threadID;
386	HFSPlusCatalogKey     nextKey;
387	HFSPlusCatalogThread  thread;
388} MissingThread;
389
390#define kDataFork	0
391#define kRsrcFork	(-1)
392#define kEAData		1
393
394struct ExtentInfo {
395	HFSCatalogNodeID fileID;
396	UInt32	startBlock;
397	UInt32 	blockCount;
398	UInt32	newStartBlock;
399	char *  attrname;
400	UInt8	forkType;
401	/* didRepair stores the result of moving of overlap extent and is used
402	 * to decide which disk blocks (original blocks or blocks allocated for
403	 * for new extent location) should be marked used and free.
404	 */
405	Boolean didRepair;
406};
407typedef struct ExtentInfo ExtentInfo;
408
409struct ExtentsTable {
410	UInt32 							count;
411	ExtentInfo 						extentInfo[1];
412};
413typedef struct ExtentsTable ExtentsTable;
414
415
416struct FileIdentifier {
417	Boolean 						hasThread;
418	HFSCatalogNodeID 				fileID;
419	HFSCatalogNodeID 				parID;			//	Used for files on HFS volumes without threads
420	Str31		 					name;			//	Used for files on HFS volumes without threads
421};
422typedef struct FileIdentifier FileIdentifier;
423
424struct FileIdentifierTable {
425	UInt32 							count;
426	FileIdentifier 					fileIdentifier[1];
427};
428typedef struct FileIdentifierTable FileIdentifierTable;
429
430/* Universal Extent Key */
431
432union ExtentKey {
433	HFSExtentKey 					hfs;
434	HFSPlusExtentKey 				hfsPlus;
435};
436typedef union ExtentKey					ExtentKey;
437/* Universal extent descriptor */
438
439union ExtentDescriptor {
440	HFSExtentDescriptor 			hfs;
441	HFSPlusExtentDescriptor 		hfsPlus;
442};
443typedef union ExtentDescriptor			ExtentDescriptor;
444/* Universal extent record */
445
446union ExtentRecord {
447	HFSExtentRecord 				hfs;
448	HFSPlusExtentRecord 			hfsPlus;
449};
450typedef union ExtentRecord				ExtentRecord;
451/* Universal catalog key */
452
453union CatalogKey {
454	HFSCatalogKey 					hfs;
455	HFSPlusCatalogKey 				hfsPlus;
456};
457typedef union CatalogKey				CatalogKey;
458/* Universal catalog data record */
459
460union CatalogRecord {
461	SInt16 							recordType;
462	HFSCatalogFolder 				hfsFolder;
463	HFSCatalogFile 					hfsFile;
464	HFSCatalogThread 				hfsThread;
465	HFSPlusCatalogFolder 			hfsPlusFolder;
466	HFSPlusCatalogFile 				hfsPlusFile;
467	HFSPlusCatalogThread 			hfsPlusThread;
468};
469typedef union CatalogRecord				CatalogRecord;
470
471/*
472  	Key for records in the attributes file.  Fields are compared in the order:
473  		cnid, attributeName, startBlock
474*/
475
476struct AttributeKey {
477	UInt16 							keyLength;					/* must set kBTBigKeysMask and kBTVariableIndexKeysMask in BTree header's attributes */
478	UInt16 							pad;
479	HFSCatalogNodeID 				cnid;						/* file or folder ID */
480	UInt32 							startBlock;					/* block # relative to start of attribute */
481	UInt16     attrNameLen;     /* number of unicode characters */
482	UInt16     attrName[127];   /* attribute name (Unicode) */
483};
484typedef struct AttributeKey				AttributeKey;
485enum {
486	kAttributeKeyMaximumLength	= sizeof(AttributeKey) - sizeof(UInt16),
487	kAttributeKeyMinimumLength	= kAttributeKeyMaximumLength - 127 * sizeof(UInt16) + sizeof(UInt16)
488};
489
490struct HIOParam {
491	QElemPtr 						qLink;						/*queue link in header*/
492	short 							qType;						/*type byte for safety check*/
493	short 							ioTrap;						/*FS: the Trap*/
494	Ptr 							ioCmdAddr;					/*FS: address to dispatch to*/
495	void* 				ioCompletion;				/*completion routine addr (0 for synch calls)*/
496	OSErr 							ioResult;					/*result code*/
497	StringPtr 						ioNamePtr;					/*ptr to Vol:FileName string*/
498	short 							ioVRefNum;					/*volume refnum (DrvNum for Eject and MountVol)*/
499	short 							ioRefNum;
500	SInt8 							ioVersNum;
501	SInt8 							ioPermssn;
502	Ptr 							ioMisc;
503	Ptr 							ioBuffer;
504	long 							ioReqCount;
505	long 							ioActCount;
506	short 							ioPosMode;
507	long 							ioPosOffset;
508};
509typedef struct HIOParam HIOParam;
510
511typedef HIOParam *						HIOParamPtr;
512
513
514struct FCBArray {
515	UInt32		length;		/* first word is FCB part length*/
516	SFCB		fcb[1];		/* fcb array*/
517};
518typedef struct FCBArray FCBArray;
519
520/*
521	UserCancel callback routine
522
523	Input:
524			progress:			number from 1 to 100 indicating current progress
525			progressChanged:	boolean flag that is true if progress number has been updated
526			context:			pointer to context data (if any) that the caller passed to CheckDisk
527
528	Output:
529			return true if the user wants to cancel the CheckDisk operation
530 */
531
532typedef int (*UserCancelProcPtr)(UInt16 progress, UInt16 secondsRemaining, Boolean progressChanged, UInt16 stage, void *context, int passno);
533
534
535#if  0
536
537	//--	User Cancel Proc
538	typedef UniversalProcPtr UserCancelUPP;
539
540	enum {
541		uppUserCancelProcInfo = kPascalStackBased
542			 | RESULT_SIZE(kTwoByteCode)
543			 | STACK_ROUTINE_PARAMETER(1, kTwoByteCode)
544			 | STACK_ROUTINE_PARAMETER(2, kTwoByteCode)
545			 | STACK_ROUTINE_PARAMETER(3, kTwoByteCode)
546			 | STACK_ROUTINE_PARAMETER(4, kTwoByteCode)
547			 | STACK_ROUTINE_PARAMETER(5, kFourByteCode)
548	};
549
550	#define NewUserCancelProc(userRoutine)		\
551			(UserCancelUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppUserCancelProcInfo, GetCurrentArchitecture())
552
553	#define CallUserCancelProc(userRoutine, progress, secondsRemaining, progressChanged, stage, context, p)		\
554			CallUniversalProc((UniversalProcPtr)(userRoutine), uppUserCancelProcInfo, (progress), (secondsRemaining), (progressChanged), (stage), (context), (p))
555
556#else /* not CFM */
557
558	typedef UserCancelProcPtr UserCancelUPP;
559
560	#define NewUserCancelProc(userRoutine)		\
561			((UserCancelUPP) (userRoutine))
562
563	#define CallUserCancelProc(userRoutine, progress, secondsRemaining, progressChanged, stage, context, p)		\
564			(*(userRoutine))((progress), (secondsRemaining), (progressChanged), (stage), (context), (p))
565
566#endif
567
568
569/*
570	UserMessage callback routine
571
572	Input:
573			message:			message from CheckDisk
574			messageType:		type of message
575			context:			pointer to context data (if any) that the caller passed to CheckDisk
576
577	Output:
578			return true if the user wants to cancel the CheckDisk operation
579 */
580
581
582typedef pascal void (*UserMessageProcPtr)(StringPtr message, SInt16 messageType, void *context);
583
584#if 0
585
586	//--	User Message Proc
587	typedef UniversalProcPtr UserMessageUPP;
588
589	enum {
590		uppUserMessageProcInfo = kPascalStackBased
591			 | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
592			 | STACK_ROUTINE_PARAMETER(2, kTwoByteCode)
593			 | STACK_ROUTINE_PARAMETER(3, kFourByteCode)
594	};
595
596	#define NewUserMessageProc(userRoutine)		\
597			(UserMessageUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppUserMessageProcInfo, GetCurrentArchitecture())
598
599	#define CallUserMessageProc(userRoutine, message, messageType, context)		\
600			CallUniversalProc((UniversalProcPtr)(userRoutine), uppUserMessageProcInfo, (message), (messageType), (context))
601
602#else /* not CFM */
603
604	typedef UserMessageProcPtr UserMessageUPP;
605
606	#define NewUserMessageProc(userRoutine)		\
607			((UserMessageUPP) (userRoutine))
608
609	#define CallUserMessageProc(userRoutine, message, messageType, context)		\
610			(*(userRoutine))((message), (messageType), (context))
611
612#endif
613
614/* 3843779 Structure to determine consistency of attribute data and
615 * corresponding bit in catalog record.  Based on Chinese Remainder
616 * Theorem
617 */
618typedef struct PrimeBuckets {
619	UInt32	n32[32];
620	UInt32	n27[27];
621	UInt32	n25[25];
622	UInt32	n7[7];
623	UInt32	n11[11];
624	UInt32	n13[13];
625	UInt32	n17[17];
626	UInt32	n19[19];
627	UInt32	n23[23];
628	UInt32	n29[29];
629	UInt32	n31[31];
630} PrimeBuckets;
631
632/* Record last attribute ID checked, used in CheckAttributeRecord, initialized in ScavSetup */
633typedef struct attributeInfo {
634	Boolean isValid;
635	Boolean hasSecurity;
636	int16_t	recordType;
637	u_int32_t fileID;
638	unsigned char attrname[XATTR_MAXNAMELEN+1];
639	u_int32_t totalBlocks;
640	u_int32_t calculatedTotalBlocks;
641	u_int64_t logicalSize;
642} attributeInfo;
643
644/*
645	VolumeObject encapsulates all infomration about the multiple volume anchor blocks (VHB and MSD)
646	on HFS and HFS+ volumes.  An HFS volume will have two MDBs (primary and alternate HFSMasterDirectoryBlock),
647	a pure HFS+ volume will have two VHBs (primary and alternate HFSPlusVolumeHeader), and a wrapped HFS+
648	volume will have two MDBs and two VHBs.
649*/
650
651/* values for VolumeObject.flags */
652enum {
653	kVO_Inited			= 0x00000001,	   	// this structured has been initialized
654	kVO_PriVHBOK		= 0x00000002,	   	// the primary Volume Header Block is valid
655	kVO_AltVHBOK		= 0x00000004,	   	// the alternate Volume Header Block is valid
656	kVO_PriMDBOK		= 0x00000008,	   	// the primary Master Directory Block is valid
657	kVO_AltMDBOK		= 0x00000010,	   	// the alternate Master Directory Block is valid
658};
659
660typedef struct VolumeObject {
661	UInt32			flags;
662	SVCB * 			vcbPtr;				// pointer to VCB used for this volume
663	UInt32			volumeType;			// (kHFSVolumeType or kEmbededHFSPlusVolumeType or kPureHFSPlusVolumeType)
664	UInt32			embeddedOffset;		// offset of embedded HFS+ (in bytes) volume into HFS wrapper volume
665										//   NOTE - UInt32 is OK since we don't support HFS Wrappers on TB volumes
666	UInt32			sectorSize;			// size of a sector for this device
667	UInt64			totalDeviceSectors;	// total number of sectors for this volume (from GetDeviceSize)
668	UInt64			totalEmbeddedSectors; // total number of sectors for embedded volume
669	// location of all possible volume anchor blocks (MDB and VHB) on this volume.  These locations
670	// are the sector offset into the volume.  Only wrapped HFS+ volumes use all 4 of these.
671	UInt64			primaryVHB;			// not used for HFS volumes
672	UInt64			alternateVHB;		// not used for HFS volumes
673	UInt64			primaryMDB;			// not used for pure HFS+ volumes
674	UInt64			alternateMDB;		// not used for pure HFS+ volumes
675} VolumeObject, *VolumeObjectPtr;
676
677
678typedef struct SGlob {
679	void *				scavStaticPtr;			// pointer to static structure allocated in ScavSetUp
680	SInt16				DrvNum;					//	drive number of target drive
681	SInt16				RepLevel;				//	repair level, 1 = minor repair, 2 = major repair
682	SInt16				ScavRes;				//	scavenge result code
683	OSErr				ErrCode;    			//	error code
684	OSErr				IntErr;     			//	internal error code
685	UInt16				VIStat;					//	scavenge status flags for volume info
686	UInt16				ABTStat;				//	scavenge status flags for Attributes BTree
687	UInt16				EBTStat;				//	scavenge status flags for extent BTree
688	UInt16				CBTStat;				//	scavenge status flags for catalog BTree
689	UInt32				CatStat;				//	scavenge status flags for catalog file
690	UInt16				VeryMinorErrorsStat;	//	scavenge status flags for very minor errors
691	UInt16				JStat;					//	scavange status flags for journal errors
692	UInt16				PrintStat;				//	info about messages that should be displayed only once
693	DrvQElPtr			DrvPtr;					//	pointer to driveQ element for target drive
694	UInt32				TarID;					//	target ID (CNID of data structure being verified)
695	UInt64				TarBlock;				//	target block/node number being verified
696	SInt16				BTLevel;				//	current BTree enumeration level
697	SBTPT				*BTPTPtr;				//	BTree path table pointer
698	SInt16				DirLevel;				//	current directory enumeration level
699	SDPR				*DirPTPtr;				//	directory path table pointer (pointer to array of SDPR)
700	uint32_t			dirPathCount;			//  number of SDPR entries allocated in directory path table
701	SInt16				CNType;					//	current CNode type
702	UInt32				ParID;					//	current parent DirID
703	CatalogName			CName;					//	current CName
704	RepairOrderPtr		MinorRepairsP;			//	ptr to list of problems for later repair
705	MissingThread		*missingThreadList;
706	Ptr 				FCBAPtr;				//	pointer to scavenger FCB array
707	UInt32				**validFilesList;		//	List of valid HFS file IDs
708
709	ExtentsTable		**overlappedExtents;	//	List of overlapped extents
710	FileIdentifierTable	**fileIdentifierTable;	//	List of files for post processing
711
712	UInt32				inputFlags;				//	Caller can specify some DFA behaviors
713
714	UInt32				volumeFeatures;			//	bit vector of volume and OS features
715	Boolean				usersAreConnected;		//	true if user are connected
716	Boolean				fileSharingOn;			//	true if file sharing is on
717	UInt32				altBlockLocation;
718	Boolean				checkingWrapper;
719	SInt16				numExtents;				//	Number of memory resident extents.  3 or 8
720	OSErr				volumeErrorCode;
721
722	UserCancelUPP		userCancelProc;
723	UserMessageUPP		userMessageProc;
724	void				*userContext;
725
726	UInt64				onePercent;
727	UInt64				itemsToProcess;
728	UInt64				itemsProcessed;
729	UInt64				lastProgress;
730	long				startTicks;
731	UInt16				secondsRemaining;
732
733	long				lastTickCount;
734
735
736	SVCB			*calculatedVCB;
737	SFCB			*calculatedExtentsFCB;
738	SFCB			*calculatedCatalogFCB;
739	SFCB			*calculatedAllocationsFCB;
740	SFCB			*calculatedAttributesFCB;
741	SFCB			*calculatedStartupFCB;
742	SFCB			*calculatedRepairFCB;
743	BTreeControlBlock	*calculatedExtentsBTCB;
744	BTreeControlBlock	*calculatedCatalogBTCB;
745	BTreeControlBlock	*calculatedRepairBTCB;
746	BTreeControlBlock	*calculatedAttributesBTCB;
747
748	Boolean			cleanUnmount;
749	Boolean			guiControl;
750	fsck_ctx_t		context;
751	int				chkLevel;
752	int             repairLevel;
753	int             rebuildOptions;			// options to indicate type of btree(s) to rebuild
754	Boolean			minorRepairErrors;	// indicates some minor repairs failed
755	Boolean		minorRepairFalseSuccess;	// indicates minor repair function is returning false success, do not delete from the list
756	int				canWrite;  	// we can safely write to the block device
757	int				writeRef;	// file descriptor with write access on the volume
758	int				lostAndFoundMode;  // used when creating lost+found directory
759	int				liveVerifyState; // indicates if live verification is being done or not
760	BTScanState		scanState;
761	int		scanCount;	/* Number of times fsck_hfs has looped */
762
763	unsigned char	volumeName[256]; /* volume name in ASCII or UTF-8 */
764	char		deviceNode[256]; /* device node in ASCII */
765
766	/* Extended attribute check related stuff */
767	uint32_t	cat_ea_count;		/* number of catalog records that have attribute bit set */
768	uint32_t	cat_acl_count;		/* number of catalog records that have security bit set */
769	uint32_t	attr_ea_count;		/* number of unique fileID attributes found in attribute btree */
770	uint32_t	attr_acl_count;		/* number of acls found in attribute btree */
771	PrimeBuckets 	CBTAttrBucket;		/* prime number buckets for Attribute bit in Catalog btree */
772	PrimeBuckets 	CBTSecurityBucket;	/* prime number buckets for Security bit in Catalog btree */
773	PrimeBuckets 	ABTAttrBucket;		/* prime number buckets for Attribute bit in Attribute btree */
774	PrimeBuckets 	ABTSecurityBucket;	/* prime number buckets for Security bit in Attribute btree */
775	attributeInfo 	lastAttrInfo; 		/* Record last attribute ID checked, used in CheckAttributeRecord, initialized in ScavSetup */
776	UInt16		securityAttrName[XATTR_MAXNAMELEN];	/* Store security attribute name in UTF16, to avoid frequent conversion */
777	size_t  	securityAttrLen;
778
779	/* File Hard Links related stuff */
780	uint32_t	filelink_priv_dir_id;
781
782	/* Directory Hard Links related stuff */
783	uint32_t	dirlink_priv_dir_id;
784	uint32_t	dirlink_priv_dir_valence;
785	uint32_t	calculated_dirinodes;
786	uint32_t	calculated_dirlinks;
787
788	/* Journal file ID's */
789	uint32_t	journal_file_id;
790	uint32_t	jib_file_id;
791} SGlob, *SGlobPtr;
792
793
794enum
795{
796	supportsTrashVolumeCacheFeatureMask		= 1,
797	supportsHFSPlusVolsFeatureMask			= 2,
798	volumeIsMountedMask						= 4
799};
800
801/* scavenger flags */
802
803/* volume info status flags (contents of VIStat) */
804
805#define	S_MDB					0x8000	//	MDB/VHB damaged
806#define	S_AltMDB				0x4000	//	Unused	/* alternate MDB damaged */
807#define	S_VBM					0x2000	//	volume bit map damaged
808#define	S_WMDB					0x1000	//	wrapper MDB is damaged
809#define	S_OverlappingExtents	0x0800	//	Overlapping extents found
810#define	S_BadMDBdrAlBlSt		0x0400	//	Invalid drAlBlSt field in MDB
811#define S_InvalidWrapperExtents	0x0200	//	Invalid catalog extent start in MDB
812
813/* BTree status flags (contents of EBTStat, CBTStat and ABTStat) */
814
815#define	S_BTH					0x8000	/* BTree header damaged */
816#define	S_BTM					0x4000	/* BTree map damaged */
817#define	S_Indx					0x2000	//	Unused	/* index structure damaged */
818#define	S_Leaf					0x1000	//	Unused	/* leaf structure damaged */
819#define S_Orphan				0x0800  // orphaned file
820#define S_OrphanedExtent		0x0400  // orphaned extent
821#define S_ReservedNotZero		0x0200  // the flags or reserved fields are not zero
822#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.
823#define S_ReservedBTH			0x0080  // fields in the BTree header should be zero but are not
824#define S_AttributeCount		0x0040	// incorrect number of xattr in attribute btree in comparison with attribute bit in catalog btree
825#define S_SecurityCount			0x0020	// incorrect number of security xattrs in attribute btree in comparison with security bit in catalog btree
826#define S_AttrRec				0x0010	// orphaned/unknown record in attribute BTree
827#define S_ParentHierarchy		0x0008	// bad parent hierarchy, could not lookup parent directory record */
828#define S_UnusedNodesNotZero	0x0004	/* Unused B-tree nodes are not filled with zeroes */
829
830/* catalog file status flags (contents of CatStat) */
831
832#define	S_IllName			0x00008000	/* illegal name found */
833#define	S_Valence			0x00004000	/* a directory valence is out of sync */
834#define	S_FThd				0x00002000	/* dangling file thread records exist */
835#define	S_DFCorruption		0x00001000	/* disappearing folder corruption detected */
836#define	S_NoDir				0x00000800	/* missing directory record */
837#define S_LockedDirName		0x00000400  // locked dir name
838#define S_MissingThread		0x00000200  /* missing thread record */
839#define S_UnlinkedFile		0x00000100	/* orphaned link node */
840#define S_LinkCount			0x00000080	/* data node link count needs repair */
841#define S_Permissions		0x00000040	/* BSD permissions need repair */
842#define S_FileAllocation	0x00000020	/* peof or leof needs adjustment */
843#define S_BadExtent			0x00000010	/* invalid extent */
844#define	S_LinkErrRepair		0x00000008	/* repairable file/directory hard link corruption detected */
845#define	S_LinkErrNoRepair	0x00000004	/* un-repairable file/directory hard link corruptions detected */
846#define	S_FileHardLinkChain	0x00000002	/* incorrect number of file hard links, doubly linked list chain needs repair */
847#define S_DirHardLinkChain	0x00000001	/* incorrect number of directory hard links, doubly linked list chain needs repair */
848
849/* VeryMinorErrorsStat */
850
851#define S_BloatedThreadRecordFound	0x8000  // 2210409, excessivly large thread record found
852
853/* user file status flags (contents of FilStat) */
854
855//#define S_LockedName			0x4000  // locked file name
856
857/* Journal status flag (contents of JStat) */
858#define S_BadJournal		0x8000	/* Bad journal content */
859#define	S_DirtyJournal		0x4000	/* Journal is dirty (needs to be replayed) */
860
861/* Print status flag (contents of PrintStat) */
862#define S_DamagedDir 		0x8000	/* message for M_LookDamagedDir already printed */
863#define S_SymlinkCreate		0x4000	/* message for E_SymlinkCreate already printed */
864
865/*------------------------------------------------------------------------------
866 ScavCtrl Interface
867------------------------------------------------------------------------------*/
868
869//	Command Codes (commands to ScavControl)
870enum
871{
872	scavInitialize		= 1,			//	Start initial volume check
873	scavVerify,							//	Start verify operation
874	scavRepair,							//	Start repair opeation
875	scavTerminate,						//	Cleanup after scavenge
876};
877
878
879//	Repair Levels
880enum
881{
882	repairLevelNoProblemsFound				= 0,
883	repairLevelRepairIfOtherErrorsExist,		//	Bloated thread records, ...
884	repairLevelVeryMinorErrors,					//	Missing Custom Icon, Locked Directory name,..., Errors that don't need fixing from CheckDisk (Installer), Non Volume corruption bugs.
885	repairLevelVolumeRecoverable,				//	Minor Volume corruption exists
886	repairLevelSomeDataLoss,					//	Overlapping extents, some data loss but no scavaging will get it back
887	repairLevelWillCauseDataLoss,				//	Missing leaf nodes, repair will lose nodes without scavaging (proceed at your own risk, check disk with other utils)
888	repairLevelCatalogBtreeRebuild,				//	Catalog Btree is damaged, repair may lose some data
889	repairLevelUnrepairable						//	DFA cannot repair volume
890};
891
892
893/* Status messages written to summary */
894enum {
895	M_FirstMessage              =  1,
896	M_LastMessage               = 29
897};
898
899
900/* Internal DFA error codes */
901enum {
902	errRebuildBtree				= -1001		/* BTree requires rebuilding. */
903};
904
905
906enum {																/*	extendFileContigMask		= 0x0002*/
907	kEFContigBit				= 1,							/*	force contiguous allocation*/
908	kEFContigMask				= 0x02,
909	kEFAllBit					= 0,							/*	allocate all requested bytes or none*/
910	kEFAllMask					= 0x01,
911	kEFNoClumpBit				= 2,							/*	Don't round up requested size to multiple of clump size*/
912	kEFNoClumpMask				= 0x04,							/*	TruncateFile option flags*/
913	kEFNoExtOvflwBit			= 3,							/*  Don't use extens overflow file */
914	kEFNoExtOvflwMask			= 0x08,
915
916	kTFTrunExtBit				= 0,							/*	truncate to the extent containing new PEOF*/
917	kTFTrunExtMask				= 1
918};
919
920
921
922// Encoding vs. Index
923//
924// For runtime table lookups and for the volume encoding bitmap we
925// need to map some encodings to keep them in a reasonable range.
926//
927
928enum {
929	kTextEncodingMacRoman		= 0L,
930	kTextEncodingMacFarsi		= 0x8C,	 /* Like MacArabic but uses Farsi digits*/
931																/* The following use script code 7, smCyrillic*/
932	kTextEncodingMacUkrainian	= 0x98,	/* The following use script code 32, smUnimplemented*/
933
934	kIndexMacUkrainian	= 48,		// MacUkrainian encoding is 152
935	kIndexMacFarsi		= 49		// MacFarsi encoding is 140
936};
937
938#define MapEncodingToIndex(e) \
939	( (e) < 48 ? (e) : ( (e) == kTextEncodingMacUkrainian ? kIndexMacUkrainian : ( (e) == kTextEncodingMacFarsi ? kIndexMacFarsi : kTextEncodingMacRoman) ) )
940
941#define MapIndexToEncoding(i) \
942	( (i) == kIndexMacFarsi ? kTextEncodingMacFarsi : ( (i) == kIndexMacUkrainian ? kTextEncodingMacUkrainian : (i) ) )
943
944#define ValidMacEncoding(e)	\
945	( ((e) < 39)  ||  ((e) == kTextEncodingMacFarsi)  ||  ((e) == kTextEncodingMacUkrainian) )
946
947
948
949
950extern	void	WriteMsg( SGlobPtr GPtr, short messageID, short messageType );
951extern	void	WriteError( SGlobPtr GPtr, short msgID, UInt32 tarID, UInt64 tarBlock );
952extern	short	CheckPause( void );
953
954/* ------------------------------- From SControl.c ------------------------------- */
955
956void			ScavCtrl( SGlobPtr GPtr, UInt32 ScavOp, short *ScavRes );
957
958extern	short	CheckForStop( SGlobPtr GPtr );
959
960
961/* ------------------------------- From SRepair.c -------------------------------- */
962
963extern	OSErr	RepairVolume( SGlobPtr GPtr );
964
965extern	int		FixDFCorruption( const SGlobPtr GPtr, RepairOrderPtr DFOrderP );
966
967extern	OSErr	ProcessFileExtents( SGlobPtr GPtr, SFCB *fcb, UInt8 forkType, UInt16 flags, Boolean isExtentsBTree, Boolean *hasOverflowExtents, UInt32 *blocksUsed  );
968
969/* Function to get return file path/name given an ID */
970extern 	OSErr 	GetSystemFileName(UInt32 fileID, char *filename, unsigned int *filenamelen);
971extern 	OSErr 	GetFileNamePathByID(SGlobPtr GPtr, UInt32 fileID, char *fullPath, unsigned int *fullPathLen, char *fileName, unsigned int *fileNameLen, u_int16_t *status);
972#define FNAME_BUF2SMALL	0x001	/* filename buffer was too small */
973#define FNAME_BIGNAME	0x002	/* filename is greater than NAME_MAX bytes */
974#define FPATH_BUF2SMALL	0x010	/* path buffer was too small */
975#define	FPATH_BIGNAME	0x020	/* intermediate component in path is greater than NAME_MAX bytes */
976#define	F_RESERVE_FILEID 0x100	/* file ID was less than kHFSFirstUserCatalogNodeID */
977
978/* ------------------------------- From SUtils.c --------------------------------- */
979
980extern	int		AllocBTN( SGlobPtr GPtr, short FilRefN, UInt32 NodeNum );
981
982extern	int		IntError( SGlobPtr GPtr, OSErr ErrCode );
983
984extern	void	RcdError( SGlobPtr GPtr, OSErr ErrCode );
985
986extern	RepairOrderPtr AllocMinorRepairOrder( SGlobPtr GPtr, size_t extraBytes );
987
988extern int IsDuplicateRepairOrder(SGlobPtr GPtr, RepairOrderPtr orig);
989
990extern void DeleteRepairOrder(SGlobPtr GPtr, RepairOrderPtr orig);
991
992extern	void	SetDFAStage( UInt32 stage );
993extern	UInt32	GetDFAGlobals( void );
994
995extern void		InitializeVolumeObject( SGlobPtr GPtr );
996extern void 	CheckEmbeddedVolInfoInMDBs( SGlobPtr GPtr );
997extern VolumeObjectPtr  GetVolumeObjectPtr( void );
998extern OSErr	GetVolumeObjectVHB( BlockDescriptor * theBlockDescPtr );
999extern void 	GetVolumeObjectBlockNum( UInt64 * theBlockNumPtr );
1000extern OSErr 	GetVolumeObjectAlternateBlock( BlockDescriptor * theBlockDescPtr );
1001extern OSErr 	GetVolumeObjectPrimaryBlock( BlockDescriptor * theBlockDescPtr );
1002extern void 	GetVolumeObjectAlternateBlockNum( UInt64 * theBlockNumPtr );
1003extern void 	GetVolumeObjectPrimaryBlockNum( UInt64 * theBlockNumPtr );
1004extern OSErr	GetVolumeObjectAlternateMDB( BlockDescriptor * theBlockDescPtr );
1005extern OSErr 	GetVolumeObjectPrimaryMDB( BlockDescriptor * theBlockDescPtr );
1006extern OSErr 	GetVolumeObjectVHBorMDB( BlockDescriptor * theBlockDescPtr );
1007extern void 	PrintName( int theCount, const UInt8 *theNamePtr, Boolean isUnicodeString );
1008extern void 	PrintVolumeObject( void );
1009extern Boolean 	VolumeObjectIsValid( void );
1010extern Boolean 	VolumeObjectIsHFSPlus( void );
1011extern Boolean 	VolumeObjectIsHFS( void );
1012extern Boolean 	VolumeObjectIsEmbeddedHFSPlus( void );
1013extern Boolean 	VolumeObjectIsPureHFSPlus( void );
1014extern Boolean	VolumeObjectIsHFSX(SGlobPtr);
1015
1016extern	void	InvalidateCalculatedVolumeBitMap( SGlobPtr GPtr );
1017
1018extern	OSErr	GetVolumeFeatures( SGlobPtr GPtr );
1019
1020OSErr	FlushAlternateVolumeControlBlock( SVCB *vcb, Boolean isHFSPlus );
1021
1022extern	void	ConvertToHFSPlusExtent(const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents);
1023
1024void add_prime_bucket_uint32(PrimeBuckets *cur, uint32_t num);
1025
1026void add_prime_bucket_uint64(PrimeBuckets *cur, uint64_t num);
1027
1028int compare_prime_buckets(PrimeBuckets *bucket1, PrimeBuckets *bucket2);
1029
1030/* ------------------------------- From CatalogCheck.c -------------------------------- */
1031
1032extern	OSErr	CheckCatalogBTree( SGlobPtr GPtr );	//	catalog btree check
1033
1034extern	OSErr	CheckFolderCount( SGlobPtr GPtr );	//	Compute folderCount
1035
1036extern int  RecordBadAllocation(UInt32 parID, unsigned char * filename, UInt32 forkType, UInt32 oldBlkCnt, UInt32 newBlkCnt);
1037
1038extern int  RecordTruncation(UInt32 parID, unsigned char * filename, UInt32 forkType, UInt64 oldSize,  UInt64 newSize);
1039
1040/* ------------------------------- From SVerify1.c -------------------------------- */
1041
1042extern	OSErr	CatFlChk( SGlobPtr GPtr );		//	catalog file check
1043
1044extern	OSErr	CatHChk( SGlobPtr GPtr );		//	catalog hierarchy check
1045
1046extern	OSErr	ExtBTChk( SGlobPtr GPtr );		//	extent btree check
1047
1048extern	OSErr	BadBlockFileExtentCheck( SGlobPtr GPtr );	//	bad block file extent check
1049
1050extern	OSErr	AttrBTChk( SGlobPtr GPtr );		//	attributes btree check
1051
1052extern	OSErr	IVChk( SGlobPtr GPtr );
1053
1054/* Operation type for CheckForClean */
1055enum {
1056	kCheckVolume,		// check if volume is clean/dirty
1057	kMarkVolumeDirty,	// mark the volume dirty
1058	kMarkVolumeClean	// mark the volume clean
1059};
1060extern	int	CheckForClean( SGlobPtr GPtr, UInt8 operation, Boolean *modified );
1061
1062extern  int	CheckIfJournaled(SGlobPtr GPtr, Boolean journal_bit_only);
1063
1064typedef struct fsckJournalInfo {
1065	int	jnlfd;	// File descriptor for journal device
1066	off_t	jnlOffset;	// Offset of journal on journal device
1067	off_t	jnlSize;	// Size of journal on same
1068	char	*name;	// Name of journal device
1069} fsckJournalInfo_t;
1070
1071extern	int	IsJournalEmpty(SGlobPtr, fsckJournalInfo_t *);
1072
1073extern	OSErr	VInfoChk( SGlobPtr GPtr );
1074
1075extern	OSErr	VLockedChk( SGlobPtr GPtr );
1076
1077extern	void	BuildExtentKey( Boolean isHFSPlus, UInt8 forkType, HFSCatalogNodeID fileNumber, UInt32 blockNumber, void * key );
1078
1079extern	OSErr	OrphanedFileCheck( SGlobPtr GPtr, Boolean *problemsFound );
1080
1081extern	int		cmpLongs (const void *a, const void *b);
1082
1083extern  int CheckAttributeRecord(SGlobPtr GPtr, const HFSPlusAttrKey *key, const HFSPlusAttrRecord *rec, UInt16 reclen);
1084
1085extern void RecordXAttrBits(SGlobPtr GPtr, UInt16 flags, HFSCatalogNodeID fileid, UInt16 btreetype);
1086
1087extern  int FindOrigOverlapFiles(SGlobPtr GPtr);
1088
1089extern  void PrintOverlapFiles (SGlobPtr GPtr);
1090
1091/* ------------------------------- From SVerify2.c -------------------------------- */
1092
1093typedef int (* CheckLeafRecordProcPtr)(SGlobPtr GPtr, void *key, void *record, UInt16 recordLen);
1094
1095extern	int  BTCheck(SGlobPtr GPtr, short refNum, CheckLeafRecordProcPtr checkLeafRecord);
1096
1097extern	int		BTMapChk( SGlobPtr GPtr, short FilRefN );
1098
1099extern	OSErr	ChkCName( SGlobPtr GPtr, const CatalogName *name, Boolean unicode );	//	check catalog name
1100
1101extern	OSErr	CmpBTH( SGlobPtr GPtr, SInt16 fileRefNum );
1102
1103extern	int		CmpBTM( SGlobPtr GPtr, short FilRefN );
1104
1105extern	int		CmpMDB( SGlobPtr GPtr, HFSMasterDirectoryBlock * mdbP);
1106
1107extern	int		CmpVBM( SGlobPtr GPtr );
1108
1109extern	OSErr	CmpBlock( void *block1P, void *block2P, size_t length ); /* same as 'memcmp', but EQ/NEQ only */
1110
1111extern	OSErr	ChkExtRec ( SGlobPtr GPtr, UInt32 fileID, const void *extents , unsigned int *lastExtentIndex);
1112
1113extern	int		BTCheckUnusedNodes(SGlobPtr GPtr, short fileRefNum, UInt16 *btStat);
1114
1115
1116/* -------------------------- From SRebuildBTree.c ------------------------- */
1117
1118extern	OSErr 	RebuildBTree( SGlobPtr theSGlobPtr, int FileID );
1119
1120
1121/* -------------------------- From SCatalog.c ------------------------- */
1122
1123extern OSErr	UpdateFolderCount( 	SVCB *vcb,
1124									HFSCatalogNodeID pid,
1125									const CatalogName *name,
1126									SInt16 newType,
1127									UInt32 hint,
1128									SInt16 valenceDelta );
1129
1130/* ------------------------------- From SExtents.c -------------------------------- */
1131OSErr	ZeroFileBlocks( SVCB *vcb, SFCB *fcb, UInt32 startingSector, UInt32 numberOfSectors );
1132
1133OSErr MapFileBlockC (
1134	SVCB		*vcb,				// volume that file resides on
1135	SFCB			*fcb,				// FCB of file
1136	UInt32			numberOfBytes,		// number of contiguous bytes desired
1137	UInt64			sectorOffset,		// starting offset within file (in 512-byte sectors)
1138	UInt64			*startSector,		// first 512-byte volume sector (NOT an allocation block)
1139	UInt32			*availableBytes);	// number of contiguous bytes (up to numberOfBytes)
1140
1141OSErr DeallocateFile(SVCB *vcb, CatalogRecord * fileRec);
1142
1143OSErr ExtendFileC (
1144	SVCB		*vcb,				// volume that file resides on
1145	SFCB			*fcb,				// FCB of file to truncate
1146	UInt32			sectorsToAdd,		// number of sectors to allocate
1147	UInt32			flags,				// EFContig and/or EFAll
1148	UInt32			*actualSectorsAdded); // number of bytes actually allocated
1149
1150OSErr FlushExtentFile( SVCB *vcb );
1151
1152void ExtDataRecToExtents(
1153	const HFSExtentRecord	oldExtents,
1154	HFSPlusExtentRecord	newExtents);
1155
1156OSErr UpdateExtentRecord (
1157	const SVCB		*vcb,
1158	SFCB					*fcb,
1159	const HFSPlusExtentKey	*extentFileKey,
1160	HFSPlusExtentRecord		extentData,
1161	UInt32					extentBTreeHint);
1162
1163OSErr ReleaseExtents(
1164	SVCB 					*vcb,
1165	const HFSPlusExtentRecord extentRecord,
1166	UInt32					*numReleasedAllocationBlocks,
1167	Boolean 				*releasedLastExtent);
1168
1169OSErr	CheckFileExtents( SGlobPtr GPtr, UInt32 fileNumber, UInt8 forkType, const unsigned char *xattrName,
1170                          const void *extents, UInt32 *blocksUsed );
1171OSErr	GetBTreeHeader( SGlobPtr GPtr, SFCB* fcb, BTHeaderRec *header );
1172OSErr	CompareVolumeBitMap( SGlobPtr GPtr, SInt32 whichBuffer );
1173OSErr	CompareVolumeHeader( SGlobPtr GPtr, HFSPlusVolumeHeader *vh );
1174OSErr	CreateExtentsBTreeControlBlock( SGlobPtr GPtr );
1175OSErr	CreateCatalogBTreeControlBlock( SGlobPtr GPtr );
1176OSErr	CreateAttributesBTreeControlBlock( SGlobPtr GPtr );
1177OSErr	CreateExtendedAllocationsFCB( SGlobPtr GPtr );
1178
1179
1180OSErr	CacheWriteInPlace( SVCB *vcb, UInt32 fileRefNum,  HIOParam *iopb, UInt64 currentPosition,
1181	UInt32 maximumBytes, UInt32 *actualBytes );
1182
1183
1184/* Generic B-tree call back routines */
1185OSStatus GetBlockProc (SFCB *filePtr, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block);
1186OSStatus ReleaseBlockProc (SFCB *filePtr, BlockDescPtr blockPtr, ReleaseBlockOptions options);
1187OSStatus SetEndOfForkProc (SFCB *filePtr, FSSize minEOF, FSSize maxEOF);
1188OSStatus SetBlockSizeProc (SFCB *filePtr, ByteCount blockSize, ItemCount minBlockCount);
1189
1190void DFA_PrepareInputName(ConstStr31Param name, Boolean isHFSPlus, CatalogName *catalogName);
1191
1192extern	UInt32	CatalogNameSize( const CatalogName *name, Boolean isHFSPlus);
1193
1194void	SetupFCB( SVCB *vcb, SInt16 refNum, UInt32 fileID, UInt32 fileClumpSize );
1195
1196
1197extern	void	CalculateItemCount( SGlob *GPtr, UInt64 *itemCount, UInt64 *onePercent );
1198
1199
1200
1201//	Macros
1202extern		BTreeControlBlock*	GetBTreeControlBlock( short refNum );
1203#define		GetBTreeControlBlock(refNum)	((BTreeControlBlock*) ResolveFCB((refNum))->fcbBtree)
1204
1205/*	The following macro marks a VCB as dirty by setting the upper 8 bits of the flags*/
1206EXTERN_API_C( void )
1207MarkVCBDirty					(SVCB *			vcb);
1208
1209#define	MarkVCBDirty(vcb)	((void) (vcb->vcbFlags |= 0xFF00))
1210EXTERN_API_C( void )
1211MarkVCBClean					(SVCB *			vcb);
1212
1213#define	MarkVCBClean(vcb)	((void) (vcb->vcbFlags &= 0x00FF))
1214EXTERN_API_C( Boolean )
1215IsVCBDirty						(SVCB *			vcb);
1216
1217#define	IsVCBDirty(vcb)		((Boolean) ((vcb->vcbFlags & 0xFF00) != 0))
1218
1219
1220extern	pascal void M_Debugger(void);
1221extern	pascal void M_DebugStr(ConstStr255Param debuggerMsg);
1222#if ( DEBUG_BUILD )
1223	#define	M_Debuger()					Debugger()
1224	#define	M_DebugStr( debuggerMsg )	DebugStr( debuggerMsg )
1225#else
1226	#define	M_Debuger()
1227	#define	M_DebugStr( debuggerMsg )
1228#endif
1229
1230
1231/*	Test for error and return if error occurred*/
1232EXTERN_API_C( void )
1233ReturnIfError					(OSErr 					result);
1234
1235#define	ReturnIfError(result)					if ( (result) != noErr ) return (result); else ;
1236/*	Test for passed condition and return if true*/
1237EXTERN_API_C( void )
1238ReturnErrorIf					(Boolean 				condition,
1239								 OSErr 					result);
1240
1241#define	ReturnErrorIf(condition, error)			if ( (condition) )	return( (error) );
1242/*	Exit function on error*/
1243EXTERN_API_C( void )
1244ExitOnError						(OSErr 					result);
1245
1246#define	ExitOnError( result )					if ( ( result ) != noErr )	goto ErrorExit; else ;
1247
1248/*	Return the low 16 bits of a 32 bit value, pinned if too large*/
1249EXTERN_API_C( UInt16 )
1250LongToShort						(UInt32 				l);
1251
1252#define	LongToShort( l )	l <= (UInt32)0x0000FFFF ? ((UInt16) l) : ((UInt16) 0xFFFF)
1253
1254
1255EXTERN_API_C( UInt32 )
1256GetDFAStage						(void);
1257
1258EXTERN_API_C(OSErr)
1259DeleteCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint, Boolean for_rename);
1260
1261EXTERN_API_C(OSErr)
1262GetCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint, CatalogRecord *data);
1263
1264EXTERN_API_C( SInt32 )
1265CompareCatalogKeys				(HFSCatalogKey *		searchKey,
1266								 HFSCatalogKey *		trialKey);
1267
1268EXTERN_API_C( SInt32 )
1269CompareExtendedCatalogKeys		(HFSPlusCatalogKey *	searchKey,
1270								 HFSPlusCatalogKey *	trialKey);
1271EXTERN_API_C( SInt32 )
1272CaseSensitiveCatalogKeyCompare (HFSPlusCatalogKey * searchKey,
1273                                HFSPlusCatalogKey * trialKey);
1274
1275EXTERN_API_C( SInt32 )
1276CompareExtentKeys				(const HFSExtentKey *	searchKey,
1277								 const HFSExtentKey *	trialKey);
1278
1279EXTERN_API_C( SInt32 )
1280CompareExtentKeysPlus			(const HFSPlusExtentKey * searchKey,
1281								 const HFSPlusExtentKey * trialKey);
1282EXTERN_API_C( SInt32 )
1283CompareAttributeKeys			(const AttributeKey * searchKey,  const AttributeKey * trialKey);
1284EXTERN_API( SFCB* )
1285ResolveFCB						(short 					fileRefNum);
1286
1287EXTERN_API_C( OSErr )
1288ValidVolumeHeader				(HFSPlusVolumeHeader *	volumeHeader);
1289
1290
1291/* Old B-tree Manager API (going away soon!) */
1292
1293EXTERN_API_C( OSErr )
1294SearchBTreeRecord				(SFCB 				*fcb,
1295								 const void *			key,
1296								 UInt32 				hint,
1297								 void *					foundKey,
1298								 void *					data,
1299								 UInt16 *				dataSize,
1300								 UInt32 *				newHint);
1301
1302EXTERN_API_C( OSErr )
1303GetBTreeRecord					(SFCB 				*fcb,
1304								 SInt16 				selectionIndex,
1305								 void *					key,
1306								 void *					data,
1307								 UInt16 *				dataSize,
1308								 UInt32 *				newHint);
1309
1310EXTERN_API_C( OSErr )
1311InsertBTreeRecord				(SFCB 				*fcb,
1312								 const void *			key,
1313								 const void *			data,
1314								 UInt16 				dataSize,
1315								 UInt32 *				newHint);
1316
1317EXTERN_API_C( OSErr )
1318DeleteBTreeRecord				(SFCB 				*fcb,
1319								 const void *			key);
1320
1321EXTERN_API_C( OSErr )
1322ReplaceBTreeRecord				(SFCB 				*fcb,
1323								 const void *			key,
1324								 UInt32 				hint,
1325								 void *					newData,
1326								 UInt16 				dataSize,
1327								 UInt32 *				newHint);
1328
1329EXTERN_API_C( void )
1330InitBTreeHeader					(UInt32 				fileSize,
1331								 UInt32 				clumpSize,
1332								 UInt16 				nodeSize,
1333								 UInt16 				recordCount,
1334								 UInt16 				keySize,
1335								 UInt32 				attributes,
1336								 UInt32 *				mapNodes,
1337								 void *					buffer);
1338
1339EXTERN_API_C( OSErr )
1340UpdateFreeCount					(SVCB *			vcb);
1341
1342
1343EXTERN_API_C(Boolean)
1344NodesAreContiguous(	SFCB		*fcb,
1345			UInt32		nodeSize);
1346
1347
1348
1349UInt32 GetTimeUTC(void);
1350UInt32 GetTimeLocal(Boolean forHFS);
1351
1352OSErr FlushVolumeControlBlock( SVCB *vcb );
1353
1354pascal short ResolveFileRefNum(SFCB * fileCtrlBlockPtr);
1355
1356extern UInt32	CatalogNameLength( const CatalogName *name, Boolean isHFSPlus);
1357
1358extern void		CopyCatalogName( const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus);
1359
1360extern	void	UpdateCatalogName( ConstStr31Param srcName, Str31 destName);
1361
1362extern	void	BuildCatalogKey( HFSCatalogNodeID parentID, const CatalogName *name, Boolean isHFSPlus,
1363								 CatalogKey *key);
1364
1365extern void		UpdateVolumeEncodings( SVCB *volume, TextEncoding encoding);
1366
1367
1368OSErr BlockAllocate (SVCB *vcb, UInt32 startingBlock, UInt32 blocksRequested, UInt32 blocksMaximum,
1369			Boolean forceContiguous, UInt32 *actualStartBlock, UInt32 *actualNumBlocks);
1370OSErr	BlockDeallocate ( SVCB *vcb, UInt32 firstBlock, UInt32 numBlocks);
1371UInt32	DivideAndRoundUp( UInt32 numerator, UInt32 denominator);
1372OSErr	BlockFindAll(SFCB *fcb, UInt32 needed);
1373
1374OSErr InitializeBlockCache ( UInt32 blockSize, UInt32 blockCount );
1375
1376void	SetFCBSPtr( Ptr value );
1377Ptr	GetFCBSPtr( void );
1378
1379
1380/*
1381 * UTF-8 conversion routines
1382 */
1383extern int utf_decodestr(const unsigned char *, size_t, u_int16_t *, size_t *, size_t);
1384extern int utf_encodestr(const u_int16_t *, size_t, unsigned char *, size_t *, size_t);
1385
1386/*
1387 * HardLink checking routines
1388 */
1389extern int   HardLinkCheckBegin(SGlobPtr gp, void** cookie);
1390extern void  HardLinkCheckEnd(void * cookie);
1391extern void  CaptureHardLink(void * cookie, const HFSPlusCatalogFile *file);
1392extern int   CheckHardLinks(void *cookie);
1393
1394extern void hardlink_add_bucket(PrimeBuckets *bucket, uint32_t inode_id, uint32_t cur_link_id);
1395extern int inode_check(SGlobPtr, PrimeBuckets *, CatalogRecord *, CatalogKey *, Boolean);
1396extern void record_link_badchain(SGlobPtr, Boolean);
1397extern int record_link_badflags(SGlobPtr, uint32_t, Boolean, uint32_t, uint32_t);
1398extern int record_inode_badflags(SGlobPtr, uint32_t, Boolean, uint32_t, uint32_t, Boolean);
1399extern int record_dirlink_badownerflags(SGlobPtr, uint32_t, uint8_t, uint8_t, int);
1400extern int record_link_badfinderinfo(SGlobPtr, uint32_t, Boolean);
1401
1402extern int get_first_link_id(SGlobPtr gptr, CatalogRecord *inode_rec, uint32_t inode_id, Boolean isdir, uint32_t *first_link_id);
1403extern int filelink_hash_inode(UInt32 inode_id, UInt32 linkCount);
1404
1405/*
1406 * Directory Hard Link checking routines
1407 */
1408extern int dirhardlink_init(SGlobPtr gptr);
1409extern int dirhardlink_check(SGlobPtr gptr);
1410
1411extern OSErr GetCatalogRecordByID(SGlobPtr GPtr, UInt32 file_id, Boolean isHFSPlus, CatalogKey *key, CatalogRecord *rec, uint16_t *recsize);
1412
1413struct HardLinkInfo;
1414extern int RepairHardLinkChains(SGlobPtr, Boolean);
1415
1416/*
1417 * Volume Bitmap checking routines
1418 */
1419extern int  BitMapCheckBegin(SGlobPtr g);
1420extern int  BitMapCheckEnd(void);
1421extern int  CaptureBitmapBits(UInt32 startBit, UInt32 bitCount);
1422extern int  ReleaseBitmapBits(UInt32 startBit, UInt32 bitCount);
1423extern int  CheckVolumeBitMap(SGlobPtr g, Boolean repair);
1424extern void UpdateFreeBlockCount(SGlobPtr g);
1425extern int 	AllocateContigBitmapBits (SVCB *vcb, UInt32 numBlocks, UInt32 *actualStartBlock);
1426extern int  IsTrimSupported(void);
1427extern void TrimFreeBlocks(SGlobPtr g);
1428
1429/*
1430 * Variables and routines to support mapping a physical block number to a
1431 * file path
1432 */
1433struct found_blocks {
1434	u_int64_t block;
1435	u_int32_t fileID;
1436	u_int32_t padding;
1437};
1438#define FOUND_BLOCKS_QUANTUM	30
1439extern int gBlkListEntries;
1440extern u_int64_t *gBlockList;
1441extern int gFoundBlockEntries;
1442extern struct found_blocks *gFoundBlocksList;
1443extern long gBlockSize;
1444void CheckPhysicalMatch(SVCB *vcb, UInt32 startblk, UInt32 blkcount, UInt32 fileNumber, UInt8 forkType);
1445void dumpblocklist(SGlobPtr GPtr);
1446
1447#ifdef __cplusplus
1448};
1449#endif
1450
1451#endif /* __SCAVENGER__ */
1452