/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (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.
 * 
 * This 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@
 */
/*	@(#)hfs.h		3.0
*
*	(c) 1990, 1992 NeXT Computer, Inc.  All Rights Reserved
*	(c) 1997-1999 Apple Computer, Inc.  All Rights Reserved
*
*	hfs.h -- constants, structures, function declarations. etc.
*			for Macintosh file system vfs.
*
*	HISTORY
* 12-Aug-1999	Scott Roberts	Merge into HFSStruct, the FCB
*  6-Jun-1999	Don Brady	Minor cleanup of hfsmount struct.
* 22-Mar-1999	Don Brady	For POSIX delete semantics: add private metadata strings.
* 13-Jan-1999	Don Brady	Add ATTR_CMN_SCRIPT to HFS_ATTR_CMN_LOOKUPMASK (radar #2296613).
* 20-Nov-1998	Don Brady	Remove UFSToHFSStr and HFSToUFSStr prototypes (obsolete).
*							Move filename entry from FCB to hfsfilemeta, hfsdirentry
*							names are now 255 byte long.
* 10-Nov-1998	Pat Dirks	Added MAXLOGBLOCKSIZE and MAXLOGBLOCKSIZEBLOCKS and RELEASE_BUFFER flag.
*                           Added hfsLogicalBlockTableEntry and h_logicalblocktable field in struct hfsnode.
*  4-Sep-1998	Pat Dirks	Added hfs_log_block_size to hfsmount struct [again] and BestBlockSizeFit routine.
* 31-aug-1998	Don Brady	Add UL to MAC_GMT_FACTOR constant.
* 04-jun-1998	Don Brady	Add hfsMoveRename prototype to replace hfsMove and hfsRename.
*							Add VRELE and VPUT macros to catch bad ref counts.
* 28-May-1998	Pat Dirks	Move internal 'struct searchinfo' def'n here from attr.h
* 03-may-1998	Brent Knight	Add gTimeZone.
* 23-apr-1998	Don Brady	Add File type and creator for symbolic links.
* 22-apr-1998	Don Brady	Removed kMetaFile.
* 21-apr-1998	Don Brady	Add to_bsd_time and to_hfs_time prototypes.
* 20-apr-1998	Don Brady	Remove course-grained hfs metadata locking.
* 15-apr-1998	Don Brady	Add hasOverflowExtents and hfs_metafilelocking prototypes. Add kSysFile constant.
* 14-apr-1998	Deric Horn	Added searchinfo_t, definition of search criteria used by searchfs.
*  9-apr-1998	Don Brady	Added hfs_flushMDB and hfs_flushvolumeheader prototypes.
*  8-apr-1998	Don Brady	Add MAKE_VREFNUM macro.
* 26-mar-1998	Don Brady	Removed CloseBTreeFile and OpenBtreeFile prototypes.
*
* 12-nov-1997 	Scott Roberts	Added changes for HFSPlus
*/

#ifndef __HFS__
#define __HFS__

#include <sys/param.h>
#include <sys/lock.h>
#include <sys/queue.h>
#include <sys/attr.h>

#include <sys/dirent.h>

#include <hfs/hfs_format.h>
#include <hfs/hfs_macos_defs.h>
#include <hfs/hfs_encodings.h>


struct uio;				// This is more effective than #include <sys/uio.h> in case KERNEL is undefined...
struct hfslockf;		// For advisory locking

/*
 *	Just reported via MIG interface.
 */
#define VERSION_STRING	"hfs-2 (4-12-99)"

#define HFS_LINK_MAX	32767

/*
 *	Set to force READ_ONLY.
 */
#define	FORCE_READONLY	0

enum { kMDBSize = 512 };				/* Size of I/O transfer to read entire MDB */

enum { kMasterDirectoryBlock = 2 };			/* MDB offset on disk in 512-byte blocks */
enum { kMDBOffset = kMasterDirectoryBlock * 512 };	/* MDB offset on disk in bytes */

enum {
	kUnknownID = 0,
	kRootParID = 1,
	kRootDirID = 2
};

enum {
	kUndefinedFork 	= 0,
	kAnyFork,
	kDataFork,
	kRsrcFork,
	kDirectory,
	kSysFile,
	kDefault
};


/*
 *	File type and creator for symbolic links
 */
enum {
	kSymLinkFileType	= 0x736C6E6B,	/* 'slnk' */
	kSymLinkCreator		= 0x72686170	/* 'rhap' */
};

#define BUFFERPTRLISTSIZE 25

extern char * gBufferAddress[BUFFERPTRLISTSIZE];
extern struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE];
extern int gBufferListIndex;
extern  simple_lock_data_t gBufferPtrListLock;

extern struct timezone gTimeZone;

/* Flag values for bexpand: */
#define RELEASE_BUFFER 0x00000001


/* Internal Data structures*/

struct vcb_t {
    int16_t			vcbFlags;
    u_int16_t 			vcbSigWord;
    u_int32_t 			vcbCrDate;
    u_int32_t 			vcbLsMod;
    int16_t 			vcbAtrb;
    u_int16_t 			vcbNmFls;			/* HFS only */
    int16_t 			vcbVBMSt;
    int16_t 			vcbAlBlSt;
    int32_t 			vcbClpSiz;
    u_int32_t 			vcbNxtCNID;
    u_int8_t		 	vcbVN[256];
    int16_t 			vcbVRefNum;
    u_int16_t 			vcbVSeqNum;
    u_int32_t 			vcbVolBkUp;
    int32_t 			vcbWrCnt;
    u_int16_t 			vcbNmRtDirs;		/* HFS only */
    u_int16_t 			vcbReserved;
    int32_t 			vcbFilCnt;
    int32_t 			vcbDirCnt;
    int32_t 			vcbFndrInfo[8];
    struct vnode *		extentsRefNum;
    struct vnode *		catalogRefNum;
    struct vnode *		allocationsRefNum;
    u_int32_t 			blockSize;			/*	size of allocation blocks - vcbAlBlkSiz*/
    u_int32_t 			totalBlocks;		/*	number of allocation blocks in volume */
    u_int32_t 			freeBlocks;			/*	number of unused allocation blocks - vcbFreeBks*/
    u_int32_t 			nextAllocation;		/*	start of next allocation search - vcbAllocPtr*/
	u_int32_t			altIDSector;		/* location of alternate MDB/VH */
    u_int32_t 			hfsPlusIOPosOffset;	/*	Disk block where HFS+ starts	*/
    u_int32_t 			checkedDate;		/*	date and time of last disk check	*/
    u_int64_t 			encodingsBitmap;	/* HFS Plus only*/
    u_int32_t	 		volumeNameEncodingHint;	/* Text encoding used for volume name*/
    char *	 			hintCachePtr;		/* points to this volumes heuristicHint cache*/
    u_int32_t 			localCreateDate;	/* creation times for HFS+ volumes are in local time */
    simple_lock_data_t	vcbSimpleLock;		/* simple lock to allow concurrent access to vcb data */
};
typedef struct vcb_t ExtendedVCB;

/* vcbFlags */
#define			kHFS_DamagedVolume			0x1	/* This volume has errors, unmount dirty */
#define 		MARK_VOLUMEDAMAGED(fcb)		FCBTOVCB((fcb))->vcbFlags |= kHFS_DamagedVolume;


/*
 * NOTE: The code relies on being able to cast an ExtendedVCB* to a vfsVCB* in order
 *	 to gain access to the mount point pointer from a pointer
 *	 to an ExtendedVCB.  DO NOT INSERT OTHER FIELDS BEFORE THE vcb FIELD!!
 *
 * vcbFlags, vcbLsMod, vcbFilCnt, vcbDirCnt, vcbNxtCNID, etc
 * are locked by the hfs_lock simple lock.
 */
typedef struct vfsVCB {
    ExtendedVCB			vcb_vcb;
    struct hfsmount		*vcb_hfsmp;				/* Pointer to hfsmount structure */
} vfsVCB_t;



/* This structure describes the HFS specific mount structure data. */
typedef struct hfsmount {
	u_long				hfs_mount_flags;
	u_int8_t			hfs_fs_clean;			/* Whether contents have been flushed in clean state */
	u_int8_t			hfs_fs_ronly;			/* Whether this was mounted as read-initially  */
	u_int8_t			hfs_unknownpermissions;	/* Whether this was mounted with MNT_UNKNOWNPERMISSIONS */
	
	/* Physical Description */
	u_long				hfs_phys_block_count;	/* Num of PHYSICAL blocks of volume */
	u_long				hfs_phys_block_size;	/* Always a multiple of 512 */

	/* Access to VFS and devices */
	struct mount		*hfs_mp;				/* filesystem vfs structure */
	struct vnode		*hfs_devvp;				/* block device mounted vnode */
	dev_t				hfs_raw_dev;			/* device mounted */
	struct netexport	hfs_export;				/* Export information */
	u_int32_t			hfs_logBlockSize;		/* Size of buffer cache buffer for I/O */
	
	/* Default values for HFS standard and non-init access */
	uid_t				hfs_uid;				/* uid to set as owner of the files */
	gid_t				hfs_gid;				/* gid to set as owner of the files */
	mode_t				hfs_dir_mask;			/* mask to and with directory protection bits */
	mode_t				hfs_file_mask;			/* mask to and with file protection bits */
	u_long				hfs_encoding;			/* Defualt encoding for non hfs+ volumes */	

	/* simple lock for shared meta renaming */
	simple_lock_data_t	hfs_renamelock;

	/* HFS Specific */
	struct vfsVCB		hfs_vcb;
	u_long			hfs_private_metadata_dir; /* private/hidden directory for unlinked files */
	u_int32_t		hfs_metadata_createdate;
	hfs_to_unicode_func_t	hfs_get_unicode;
	unicode_to_hfs_func_t	hfs_get_hfsname;
} hfsmount_t;


/*****************************************************************************
*
*	hfsnode structure
*
*
*
*****************************************************************************/

#define MAXHFSVNODELEN		31
typedef u_char FileNameStr[MAXHFSVNODELEN+1];

CIRCLEQ_HEAD(siblinghead, hfsnode)	;	/* Head of the sibling list */


struct  hfsnode {
	LIST_ENTRY(hfsnode) h_hash;		/* links on valid files */
	CIRCLEQ_ENTRY(hfsnode) h_sibling;	/* links on siblings */
	struct lock__bsd__	h_lock;		/* node lock. */
	union {
		struct hfslockf *hu_lockf;	/* Head of byte-level lock list. */
		void            *hu_sysdata;	/* private data for system files */
	} h_un;
	struct vnode *		h_vp;		/* vnode associated with this inode. */
	struct hfsfilemeta *	h_meta;		/* Ptr to file meta data */
	u_int16_t		h_nodeflags;	/* flags, see below */
	u_int8_t		h_type;		/* Type of info: dir, data, rsrc */
	int8_t 			fcbFlags;	/* FCB flags */
	u_int64_t 		fcbEOF;		/* Logical length or EOF in bytes */
	u_int64_t 		fcbPLen;	/* Physical file length in bytes */
	u_int64_t 		fcbMaxEOF;	/* Maximum logical length or EOF in bytes */
	u_int32_t 		fcbClmpSize;	/* Number of bytes per clump */
	HFSPlusExtentRecord	fcbExtents;	/* Extents of file */

#if HFS_DIAGNOSTIC
	u_int32_t		h_valid;	/* is the vnode reference valid */
#endif
};
#define	h_lockf		h_un.hu_lockf
#define	fcbBTCBPtr	h_un.hu_sysdata

typedef struct hfsnode FCB;


typedef struct hfsfilemeta {
	struct	siblinghead h_siblinghead;		/* Head of the sibling list */
	simple_lock_data_t	h_siblinglock;		/* sibling list lock. */
	u_int32_t			h_metaflags;		/* IN_LONGNAME, etc */
	struct vnode		*h_devvp;			/* vnode for block I/O. */

	dev_t				h_dev;				/* Device associated with the inode. */
	u_int32_t			h_nodeID;			/* specific id of this node */
	u_int32_t			h_dirID;			/* Parent Directory ID */
	u_int32_t			h_hint;				/* Catalog hint */

	off_t				h_size;				/* Total physical size of object */
	u_int16_t			h_usecount;			/* How many siblings */
	u_int16_t			h_mode;				/* IFMT, permissions; see below. */
	u_int32_t			h_pflags;			/* Permission flags (NODUMP, IMMUTABLE, APPEND etc.) */
	u_int32_t			h_uid;				/* File owner. */
	u_int32_t			h_gid;				/* File group. */
	union {
	    dev_t		hu_rdev;	/* Special device info for this node */
	    u_int32_t		hu_indnodeno;	/* internal indirect node number (never exported) */
	} h_spun;
	u_int32_t			h_crtime;			/* BSD-format creation date in secs. */
	u_int32_t			h_atime;			/* BSD-format access date in secs. */
	u_int32_t			h_mtime;			/* BSD-format mod date in seconds */
	u_int32_t			h_ctime;			/* BSD-format status change date */
	u_int32_t			h_butime;			/* BSD-format last backup date in secs. */
	u_int16_t			h_nlink;			/* link count (aprox. for dirs) */
	u_short				h_namelen;			/* Length of name string */
	char *				h_namePtr;			/* Points the name of the file */
	FileNameStr			h_fileName;			/* CName of file */
} hfsfilemeta;
#define	h_rdev		h_spun.hu_rdev
#define	h_indnodeno	h_spun.hu_indnodeno

#define H_EXTENDSIZE(VP,BYTES)	((VP)->h_meta->h_size += (BYTES))
#define H_TRUNCSIZE(VP,BYTES)	((VP)->h_meta->h_size -= (BYTES))

#define MAKE_INODE_NAME(name,linkno) \
	    (void) sprintf((name), "%s%d", HFS_INODE_PREFIX, (linkno))


/*
 *	Macros for quick access to fields buried in the fcb inside an hfs node:
 */
#define H_FORKTYPE(HP)	((HP)->h_type)
#define H_FILEID(HP)	((HP)->h_meta->h_nodeID)
#define H_DIRID(HP)		((HP)->h_meta->h_dirID)
#define H_NAME(HP)		((HP)->h_meta->h_namePtr)
#define H_HINT(HP)		((HP)->h_meta->h_hint)
#define H_DEV(HP)		((HP)->h_meta->h_dev)

/* These flags are kept in flags. */
#define IN_ACCESS		0x0001		/* Access time update request. */
#define IN_CHANGE		0x0002		/* Change time update request. */
#define IN_UPDATE		0x0004		/* Modification time update request. */
#define IN_MODIFIED 	0x0008		/* Node has been modified. */
#define IN_RENAME		0x0010		/* Node is being renamed. */
#define IN_SHLOCK		0x0020		/* File has shared lock. */
#define IN_EXLOCK		0x0040		/* File has exclusive lock. */
#define IN_ALLOCATING	0x1000		/* vnode is in transit, wait or ignore */
#define IN_WANT			0x2000		/* Its being waited for */

/* These flags are kept in meta flags. */
#define IN_LONGNAME 	0x0400		/* File has long name buffer. */
#define IN_UNSETACCESS	0x0200		/* File has unset access. */
#define IN_DELETED	0x0800		/* File has been marked to be deleted */
#define IN_NOEXISTS	0x1000		/* File has been deleted, catalog entry is gone */
#if HFS_HARDLINKS
#define	IN_DATANODE	0x2000		/* File is a data node (hard-linked) */
#endif


/* File permissions stored in mode */
#define IEXEC			0000100		/* Executable. */
#define IWRITE			0000200		/* Writeable. */
#define IREAD			0000400		/* Readable. */
#define ISVTX			0001000		/* Sticky bit. */
#define ISGID			0002000		/* Set-gid. */
#define ISUID			0004000		/* Set-uid. */

/* File types */
#define IFMT			0170000		/* Mask of file type. */
#define IFIFO			0010000		/* Named pipe (fifo). */
#define IFCHR			0020000		/* Character device. */
#define IFDIR			0040000		/* Directory file. */
#define IFBLK			0060000		/* Block device. */
#define IFREG			0100000		/* Regular file. */
#define IFLNK			0120000		/* Symbolic link. */
#define IFSOCK			0140000		/* UNIX domain socket. */
#define IFWHT			0160000		/* Whiteout. */

/* Value to make sure vnode is real and defined */
#define HFS_VNODE_MAGIC 0x4846532b	/* 'HFS+' */

/* To test wether the forkType is a sibling type */
#define SIBLING_FORKTYPE(FORK) 	((FORK==kDataFork) || (FORK==kRsrcFork))

/*
 *	Write check macro
 */
#define	WRITE_CK(VNODE, FUNC_NAME)	{				\
    if ((VNODE)->v_mount->mnt_flag & MNT_RDONLY) {			\
        DBG_ERR(("%s: ATTEMPT TO WRITE A READONLY VOLUME\n", 	\
                 FUNC_NAME));	\
                     return(EROFS);							\
    }									\
}


/*
 *	hfsmount locking and unlocking.
 *
 *	mvl_lock_flags
 */
#define MVL_LOCKED    0x00000001	/* debug only */

#if	HFS_DIAGNOSTIC
#define MVL_LOCK(mvip)    {				\
    (simple_lock(&(mvip)->mvl_lock));			\
        (mvip)->mvl_flags |= MVL_LOCKED;			\
}

#define MVL_UNLOCK(mvip)    {				\
    if(((mvip)->mvl_flags & MVL_LOCKED) == 0) {		\
        panic("MVL_UNLOCK - hfsnode not locked");	\
    }							\
    (simple_unlock(&(mvip)->mvl_lock));			\
        (mvip)->mvl_flags &= ~MVL_LOCKED;			\
}
#else	/* HFS_DIAGNOSTIC */
#define MVL_LOCK(mvip)		(simple_lock(&(mvip)->mvl_lock))
#define MVL_UNLOCK(mvip)	(simple_unlock(&(mvip)->mvl_lock))
#endif	/* HFS_DIAGNOSTIC */


/* structure to hold a "." or ".." directory entry (12 bytes) */
typedef struct hfsdotentry {
	u_int32_t	d_fileno;	/* unique file number */
	u_int16_t	d_reclen;	/* length of this structure */
	u_int8_t	d_type;		/* dirent file type */
	u_int8_t	d_namelen;	/* len of filename */
	char		d_name[4];	/* "." or ".." */
} hfsdotentry;

#define AVERAGE_HFSDIRENTRY_SIZE  (8+22+4)
#define MAX_HFSDIRENTRY_SIZE	sizeof(struct dirent)

#define DIRENTRY_SIZE(namlen) \
    ((sizeof(struct dirent) - (NAME_MAX+1)) + (((namlen)+1 + 3) &~ 3))

enum {
	kCatNameIsAllocated 	= 0x1,			/* The name is malloc'd and is in cnm_nameptr */
	kCatNameIsMangled 		= 0x2,			/* The name is mangled */
	kCatNameUsesReserved 	= 0x4,			/* It overides the space reserved by cnm_namespace into cndu_extra, careful */
	kCatNameIsConsumed 		= 0x8,			/* The name has been already processed, no freeing or work is needed */
	kCatNameNoCopyName	 	= 0x10,			/* Dont copy the name */
	kCatNameMangleName	 	= 0x20			/* Mangle name if greater than passed in length */
};

/*
 * CatalogNameSpecifier is a structure that contains a name and possibly its form
 *
 * Special care needs to be taken with the flags, they can cause side effects.
 */
struct CatalogNameSpecifier {
	u_int16_t		cnm_flags;			/* See above */
	u_int16_t		cnm_length;			/* Length of the name */
	u_int32_t		cnm_parID;			/* ID of the parent directory */
	unsigned char	*cnm_nameptr;		/* If allocated, a ptr to the space, else NULL */
	unsigned char	cnm_namespace[MAXHFSVNODELEN+1]; /* Space where the name can be kept */
};
/*
 * NOTE IT IS REQUIRED that KMaxMangleNameLen >= MAXHFSVNODELEN
 * Also the total size of CatalogNameSpecifier should be less then cndu_extra, which
 * currently it easily is, this is not a requirement, just a nicety.
 *
 * The rules to how to store a name:
 * If its less than MAXHFSVNODELEN always store it in cnm_namespace.
 * If we can get by doing mangling then cnm_namespace
 * else allocate the space needed to cnm_nameptr.
 * This reflects what is done at vnode creation.
 */


enum {
	kCatalogFolderNode = 1,
	kCatalogFileNode = 2
};

/* 
 * CatalogNodeData has same layout as the on-disk HFS Plus file/dir records.
 * Classic hfs file/dir records are converted to match this layout.
 * 
 * The cnd_extra padding allows big hfs plus thread records (520 bytes max)
 * to be read onto this stucture during a cnid lookup.
 *
 * IMPORTANT!!!!!!
 * After declaring this structure, you must use the macro INIT_CATALOGDATA to prepare it
 * and CLEAN_CATALOGDATA after using it, to clean any allocated structures.
 *
 * If you do not need to have the name, then pass in kCatNameNoCopyName for flags
 */
struct CatalogNodeData {
	int16_t			cnd_type;
	u_int16_t		cnd_flags;
	u_int32_t		cnd_valence;	/* dirs only */
	u_int32_t		cnd_nodeID;
	u_int32_t		cnd_createDate;
	u_int32_t		cnd_contentModDate;
	u_int32_t		cnd_attributeModDate;
	u_int32_t		cnd_accessDate;
	u_int32_t		cnd_backupDate;
	u_int32_t 		cnd_ownerID;
	u_int32_t 		cnd_groupID;
	u_int8_t 		cnd_adminFlags;  /* super-user changeable flags */
	u_int8_t 		cnd_ownerFlags;  /* owner changeable flags */
	u_int16_t 		cnd_mode;        /* file type + permission bits */
	union {
	    u_int32_t	cndu_iNodeNum;   /* indirect links only */
	    u_int32_t	cndu_linkCount;  /* indirect nodes only */
	    u_int32_t 	cndu_rawDevice;  /* special files (FBLK and FCHR) only */
	} cnd_un;
	u_int8_t		cnd_finderInfo[32];
	u_int32_t 		cnd_textEncoding;
	u_int32_t		cnd_reserved;
	HFSPlusForkData	cnd_datafork;
	HFSPlusForkData	cnd_rsrcfork;
	u_int32_t	cnd_iNodeNumCopy;
	u_int8_t	cnd_extra[268];	/* make struct at least 520 bytes long */
	struct CatalogNameSpecifier		cnd_namespecifier;
};
typedef struct CatalogNodeData CatalogNodeData;

#define	cnd_iNodeNum		cnd_un.cndu_iNodeNum
#define	cnd_linkCount		cnd_un.cndu_linkCount
#define	cnd_rawDevice		cnd_un.cndu_rawDevice

#define	cnm_flags		cnd_namespecifier.cnm_flags
#define	cnm_length		cnd_namespecifier.cnm_length
#define	cnm_parID		cnd_namespecifier.cnm_parID
#define	cnm_nameptr		cnd_namespecifier.cnm_nameptr
#define	cnm_namespace		cnd_namespecifier.cnm_namespace

#define INIT_CATALOGDATA(C,F)	do { bzero(&((C)->cnd_namespecifier), sizeof(struct CatalogNameSpecifier)); (C)->cnm_flags=(F);}while(0);
#if HFS_DIAGNOSTIC
extern void debug_check_catalogdata(struct CatalogNodeData *cat);
#define CLEAN_CATALOGDATA(C)	do { debug_check_catalogdata(C); \
											if ((C)->cnm_flags & kCatNameIsAllocated) {\
											FREE((C)->cnm_nameptr, M_TEMP);\
											(C)->cnm_flags &= ~kCatNameIsAllocated;\
											(C)->cnm_nameptr = NULL;\
											}}while(0);
#else
#define CLEAN_CATALOGDATA(C)	do { if ((C)->cnm_flags & kCatNameIsAllocated) {\
											FREE((C)->cnm_nameptr, M_TEMP);\
											(C)->cnm_flags &= ~kCatNameIsAllocated;\
											(C)->cnm_nameptr = NULL;\
											}}while(0);
#endif

/* structure to hold a catalog record information */
/* Of everything you wanted to know about a catalog entry, file and directory */
typedef struct hfsCatalogInfo {
    CatalogNodeData 	nodeData;
    u_int32_t				hint;
} hfsCatalogInfo;

enum { kHFSPlusMaxFileNameBytes = kHFSPlusMaxFileNameChars * 3 };

enum { kdirentMaxNameBytes = NAME_MAX };

//	structure definition of the searchfs system trap for the search criterea.
struct directoryInfoSpec
{
	u_long				numFiles;
};

struct fileInfoSpec
{
	off_t				dataLogicalLength;
	off_t				dataPhysicalLength;
	off_t				resourceLogicalLength;
	off_t				resourcePhysicalLength;
};

struct searchinfospec
{
	u_char				name[kHFSPlusMaxFileNameBytes];
	u_long				nameLength;
	char				attributes;		// see IM:Files 2-100
	u_long				nodeID;
	u_long				parentDirID;
	struct timespec		creationDate;		
	struct timespec		modificationDate;		
	struct timespec		changeDate;	
	struct timespec		lastBackupDate;	
	u_long				finderInfo[8];
	uid_t				uid;	
	gid_t				gid;
	mode_t				mask;
    struct fileInfoSpec f;
	struct directoryInfoSpec d;
};
typedef struct searchinfospec searchinfospec_t;

#define HFSTIMES(hp, t1, t2) {						\
	if ((hp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) {	\
		(hp)->h_nodeflags |= IN_MODIFIED;				\
		if ((hp)->h_nodeflags & IN_ACCESS) {			\
			(hp)->h_meta->h_atime = (t1)->tv_sec;			\
		};											\
		if ((hp)->h_nodeflags & IN_UPDATE) {			\
			(hp)->h_meta->h_mtime = (t2)->tv_sec;			\
		}											\
		if ((hp)->h_nodeflags & IN_CHANGE) {			\
			(hp)->h_meta->h_ctime = time.tv_sec;			\
		};											\
		(hp)->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);	\
	}								\
}

/* This overlays the fid structure (see mount.h). */
struct hfsfid {
	u_int16_t hfsfid_len;	/* Length of structure. */
	u_int16_t hfsfid_pad;	/* Force 32-bit alignment. */
							/* The following data is filesystem-dependent, up to MAXFIDSZ (16) bytes: */
	u_int32_t hfsfid_cnid;	/* Catalog node ID. */
	u_int32_t hfsfid_gen;	/* Generation number (create date). */
};

/* macro to determine if hfs or hfsplus */
#define ISHFSPLUS(VCB) ((VCB)->vcbSigWord == kHFSPlusSigWord)
#define ISHFS(VCB) ((VCB)->vcbSigWord == kHFSSigWord)


/*
 * Various ways to acquire a VNode pointer:
 */
#define HTOV(HP) ((HP)->h_vp)

/*
 * Various ways to acquire an HFS Node pointer:
 */
#define VTOH(VP) ((struct hfsnode *)((VP)->v_data))
#define FCBTOH(FCB) ((struct hfsnode *)FCB)

/*
 * Various ways to acquire an FCB pointer:
 */
#define HTOFCB(HP) (HP)
#define VTOFCB(VP) ((FCB *)((VP)->v_data))		/* Should be the same as VTOH */

/*
 * Various ways to acquire a VFS mount point pointer:
 */
#define VTOVFS(VP) ((VP)->v_mount)
#define	HTOVFS(HP) ((HP)->h_vp->v_mount)
#define FCBTOVFS(FCB) ((FCB)->h_vp->v_mount)
#define HFSTOVFS(HFSMP) ((HFSMP)->hfs_mp)
#define VCBTOVFS(VCB) (((struct vfsVCB *)(VCB))->vcb_hfsmp->hfs_mp)

/*
 * Various ways to acquire an HFS mount point pointer:
 */
#define VTOHFS(VP) ((struct hfsmount *)((VP)->v_mount->mnt_data))
#define	HTOHFS(HP) ((struct hfsmount *)(HP)->h_vp->v_mount->mnt_data)
#define FCBTOHFS(FCB) ((struct hfsmount *)(FCB)->h_vp->v_mount->mnt_data)
#define	VFSTOHFS(MP) ((struct hfsmount *)(MP)->mnt_data)	
#define VCBTOHFS(VCB) (((struct vfsVCB *)(VCB))->vcb_hfsmp)

/*
 * Various ways to acquire a VCB pointer:
 */
#define VTOVCB(VP) (&(((struct hfsmount *)((VP)->v_mount->mnt_data))->hfs_vcb.vcb_vcb))
#define HTOVCB(HP) (&(((struct hfsmount *)((HP)->h_vp->v_mount->mnt_data))->hfs_vcb.vcb_vcb))
#define FCBTOVCB(FCB) (&(((struct hfsmount *)((FCB)->h_vp->v_mount->mnt_data))->hfs_vcb.vcb_vcb))
#define VFSTOVCB(MP) (&(((struct hfsmount *)(MP)->mnt_data)->hfs_vcb.vcb_vcb))
#define HFSTOVCB(HFSMP) (&(HFSMP)->hfs_vcb.vcb_vcb)


#define E_NONE	0
#define kHFSBlockSize 512
#define kHFSBlockShift 9	/* 2^9 = 512 */

#define IOBLKNOFORBLK(STARTINGBLOCK, BLOCKSIZEINBYTES) ((daddr_t)((STARTINGBLOCK) / ((BLOCKSIZEINBYTES) >> 9)))
#define IOBLKCNTFORBLK(STARTINGBLOCK, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \
    ((int)(IOBLKNOFORBYTE(((STARTINGBLOCK) * 512) + (BYTESTOTRANSFER) - 1, (BLOCKSIZEINBYTES)) - \
           IOBLKNOFORBLK((STARTINGBLOCK), (BLOCKSIZEINBYTES)) + 1))
#define IOBYTECCNTFORBLK(STARTINGBLOCK, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \
    (IOBLKCNTFORBLK((STARTINGBLOCK),(BYTESTOTRANSFER),(BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES))
#define IOBYTEOFFSETFORBLK(STARTINGBLOCK, BLOCKSIZEINBYTES) \
    (((STARTINGBLOCK) * 512) - \
     (IOBLKNOFORBLK((STARTINGBLOCK), (BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES)))

#define IOBLKNOFORBYTE(STARTINGBYTE, BLOCKSIZEINBYTES) ((daddr_t)((STARTINGBYTE) / (BLOCKSIZEINBYTES)))
#define IOBLKCNTFORBYTE(STARTINGBYTE, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \
((int)(IOBLKNOFORBYTE((STARTINGBYTE) + (BYTESTOTRANSFER) - 1, (BLOCKSIZEINBYTES)) - \
           IOBLKNOFORBYTE((STARTINGBYTE), (BLOCKSIZEINBYTES)) + 1))
#define IOBYTECNTFORBYTE(STARTINGBYTE, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \
    (IOBLKCNTFORBYTE((STARTINGBYTE),(BYTESTOTRANSFER),(BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES))
#define IOBYTEOFFSETFORBYTE(STARTINGBYTE, BLOCKSIZEINBYTES) ((STARTINGBYTE) - (IOBLKNOFORBYTE((STARTINGBYTE), (BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES)))

#define MAKE_VREFNUM(x)	((int32_t)((x) & 0xffff))
/*
 *	This is the straight GMT conversion constant:
 *	00:00:00 January 1, 1970 - 00:00:00 January 1, 1904
 *	(3600 * 24 * ((365 * (1970 - 1904)) + (((1970 - 1904) / 4) + 1)))
 */
#define MAC_GMT_FACTOR		2082844800UL

#define HFS_ATTR_CMN_LOOKUPMASK (ATTR_CMN_SCRIPT | ATTR_CMN_FNDRINFO | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)
#define HFS_ATTR_DIR_LOOKUPMASK (ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT)
#define HFS_ATTR_FILE_LOOKUPMASK (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
									ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
									ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS)

u_int32_t to_bsd_time(u_int32_t hfs_time);
u_int32_t to_hfs_time(u_int32_t bsd_time);

int hfs_flushfiles(struct mount *mp, int flags);
short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor);
short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor);

short hfs_getcatalog (ExtendedVCB *vcb, u_int32_t dirID, char *name, short len, hfsCatalogInfo *catInfo);
short hfsMoveRename (ExtendedVCB *vcb, u_int32_t oldDirID, char *oldName, u_int32_t newDirID, char *newName, u_int32_t *hint);
short hfsCreate (ExtendedVCB *vcb, u_int32_t dirID, char *name, int mode);
short hfsCreateFileID (ExtendedVCB *vcb, u_int32_t parentDirID, StringPtr name, u_int32_t catalogHint, u_int32_t *fileIDPtr);
short hfs_vcreate (ExtendedVCB *vcb, hfsCatalogInfo *catInfo, u_int8_t forkType, struct vnode **vpp);
short hfsDelete (ExtendedVCB *vcb, u_int32_t parentDirID, StringPtr name, short isfile, u_int32_t catalogHint);
short hfsUnmount(struct hfsmount *hfsmp, struct proc *p);

extern int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p);
extern int hasOverflowExtents(struct hfsnode *hp);

void hfs_set_metaname(char *, struct hfsfilemeta *, struct hfsmount *);

short MacToVFSError(OSErr err);
int hfs_owner_rights(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus);

void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData);
void CopyCatalogToHFSNode(struct hfsCatalogInfo *catalogInfo, struct hfsnode *hp);
u_long FindMetaDataDirectory(ExtendedVCB *vcb);


short make_dir_entry(FCB **fileptr, char *name, u_int32_t fileID);

int AttributeBlockSize(struct attrlist *attrlist);
void PackCommonAttributeBlock(struct attrlist *alist,
							  struct vnode *vp,
							  struct hfsCatalogInfo *catInfo,
							  void **attrbufptrptr,
							  void **varbufptrptr);
void PackVolAttributeBlock(struct attrlist *alist,
						   struct vnode *vp,
						   struct hfsCatalogInfo *catInfo,
						   void **attrbufptrptr,
						   void **varbufptrptr);
void PackFileDirAttributeBlock(struct attrlist *alist,
							   struct vnode *vp,
							   struct hfsCatalogInfo *catInfo,
							   void **attrbufptrptr,
							   void **varbufptrptr);
void PackForkAttributeBlock(struct attrlist *alist,
							struct vnode *vp,
							struct hfsCatalogInfo *catInfo,
							void **attrbufptrptr,
							void **varbufptrptr);
void PackAttributeBlock(struct attrlist *alist,
						struct vnode *vp,
						struct hfsCatalogInfo *catInfo,
						void **attrbufptrptr,
						void **varbufptrptr);
void PackCatalogInfoAttributeBlock (struct attrlist *alist,
						struct vnode * root_vp,
						struct hfsCatalogInfo *catInfo,
						void **attrbufptrptr,
						void **varbufptrptr);
void UnpackCommonAttributeBlock(struct attrlist *alist,
							  struct vnode *vp,
							  struct hfsCatalogInfo *catInfo,
							  void **attrbufptrptr,
							  void **varbufptrptr);
void UnpackAttributeBlock(struct attrlist *alist,
						struct vnode *vp,
						struct hfsCatalogInfo *catInfo,
						void **attrbufptrptr,
						void **varbufptrptr);
unsigned long BestBlockSizeFit(unsigned long allocationBlockSize,
                               unsigned long blockSizeLimit,
                               unsigned long baseMultiple);

OSErr	hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb,
		u_long sectors, struct proc *p);
OSErr	hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
		u_long embBlkOffset, u_long sectors, struct proc *p);
OSStatus  GetInitializedVNode(struct hfsmount *hfsmp, struct vnode **tmpvnode, int init_ubc);

int hfs_getconverter(u_int32_t encoding, hfs_to_unicode_func_t *get_unicode,
		     unicode_to_hfs_func_t *get_hfsname);

int hfs_relconverter(u_int32_t encoding);

int hfs_to_utf8(ExtendedVCB *vcb, Str31 hfs_str, ByteCount maxDstLen,
		ByteCount *actualDstLen, unsigned char* dstStr);

int utf8_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, const unsigned char* srcStr,
		Str31 dstStr);

int mac_roman_to_utf8(Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen,
		unsigned char* dstStr);

int utf8_to_mac_roman(ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr);

#endif /* __HFS__ */
