/*

Copyright (c) 1992  Microsoft Corporation

Module Name:

	forks.h

Abstract:

	This module contains the data structures to handle open forks.

Author:

	Jameel Hyder (microsoft!jameelh)


Revision History:
	25 Apr 1992		Initial Version

Notes:	Tab stop: 4
--*/

#ifndef _FORKS_
#define _FORKS_

// Afp Open modes
#define	FORK_OPEN_NONE		0x00
#define	FORK_OPEN_READ		0x01
#define	FORK_OPEN_WRITE		0x02
#define	FORK_OPEN_READWRITE	0x03
#define	FORK_OPEN_MASK		0x03

// The Deny mode values are shifted left 2 bits and or'd with the open modes
// in AfpOpenFork() API.
#define	FORK_DENY_SHIFT		4

#define	FORK_DENY_NONE		0x00
#define	FORK_DENY_READ		0x01
#define	FORK_DENY_WRITE		0x02
#define	FORK_DENY_ALL		0x03
#define	FORK_DENY_MASK		0x03

// AfpOpenFork SubFunction values
#define	FORK_DATA			0
#define	FORK_RSRC			0x80

#define	AFP_UNLOCK_FLAG		1
#define	AFP_END_FLAG		0x80

/*
 * A ForkLock describes a lock on the fork. The locks are anchored at the
 * OpenForkDesc structure. The list describes all locks for this fork by
 * all sessions and all OForkRefNums. flo_key and flo_OForkRefNum identifies
 * the lock uniquely.
 */
#if DBG
#define	FORKLOCK_SIGNATURE			*(DWORD *)"FLO"
#define	VALID_FORKLOCK				(((pForkLock) != NULL) && \
									 ((pForkLock)->Signature == FORKLOCK_SIGNATURE))
#else
#define	VALID_FORKLOCK				((pForkLock) != NULL)
#endif

// Forward reference for the ForkLock structure
struct	_OpenForkEntry;

typedef struct _ForkLock
{
#if	DBG
	DWORD					Signature;
#endif
	struct _ForkLock *		flo_Next;		// ForkDesc links
	struct _OpenForkEntry * flo_pOpenForkEntry;
											// The owning OFE for this lock
	LONG					flo_Offset;		// Beginning of lock
	LONG					flo_Size;		// Size of lock
	DWORD					flo_Key;		// Key for this lock, essentially the
											// SessionId from the SDA
} FORKLOCK, *PFORKLOCK;

/*
 * An OpenForkDesc represents an open-fork. The list is anchored at the volume
 * Descriptor. There is exactly one entry per file/fork. Multiple instances of
 * open just ups the reference count. The list of locks originating here is for
 * all instances. A back link to the Volume descriptor exists for comfort.
 */
#if	DBG
#define	OPENFORKDESC_SIGNATURE		*(DWORD *)"OFD"
#define	VALID_OPENFORKDESC(pOpenForkDesc)	(((pOpenForkDesc) != NULL) && \
						((pOpenForkDesc)->Signature == OPENFORKDESC_SIGNATURE))
#else
#define	VALID_OPENFORKDESC(pOpenForkDesc)	((pOpenForkDesc) != NULL)
#endif

typedef struct _OpenForkDesc
{
#if	DBG
	DWORD					Signature;
#endif
	struct _OpenForkDesc *	ofd_Next;			// Volume links
	struct _OpenForkDesc **	ofd_Prev;			// Volume links

	struct _VolDesc *		ofd_pVolDesc;		// Pointer to the volume descriptor
	PFORKLOCK				ofd_pForkLock;		// List of file locks
	DWORD					ofd_FileNumber;		// File number of the open file
	LONG					ofd_UseCount;		// Number of OpenForkEntry refs.
	USHORT					ofd_cOpenR;			// # of instances of open for read
	USHORT					ofd_cOpenW;			// # of instances of open for write
	USHORT					ofd_cDenyR;			// # of instances of deny read
	USHORT					ofd_cDenyW;			// # of instances of deny write
	USHORT					ofd_NumLocks;		// Number of file locks
	USHORT					ofd_Flags;			// OPEN_FORK_xxx bits
	KSPIN_LOCK				ofd_Lock;			// Lock for this descriptor
	UNICODE_STRING			ofd_FileName;		// Name of the file (w/o the stream)
	UNICODE_STRING			ofd_FilePath;		// Volume relative path to the file
} OPENFORKDESC, *POPENFORKDESC;


#define	OPEN_FORK_RESOURCE			True
#define	OPEN_FORK_DATA				False
#define	OPEN_FORK_CLOSING			0x8000
// To determine whether FlushFork of resource should really take the current
// ChangeTime to be the LastWriteTime
#define OPEN_FORK_WRITTEN			0x0100

/*
 * An OpenForkEntry represents an OForkRefNum. Every instance of an open
 * fork has an entry here. This list is anchored in the SDA. A global open
 * fork list used by the admin APIs is also linked to this.
 */
#if DBG
#define	OPENFORKENTRY_SIGNATURE		*(DWORD *)"OFE"
#define	VALID_OPENFORKENTRY(pOpenForkEntry)	\
						(((pOpenForkEntry) != NULL) && \
						 ((pOpenForkEntry)->Signature == OPENFORKENTRY_SIGNATURE))
#else
#define	VALID_OPENFORKENTRY(pOpenForkEntry) ((pOpenForkEntry) != NULL)
#endif

typedef struct _OpenForkEntry
{
#if	DBG
	DWORD					Signature;
#endif

	struct _OpenForkEntry *	ofe_Next;			// Global links
	struct _OpenForkEntry **ofe_Prev;			// Global links

	struct _OpenForkDesc *	ofe_pOpenForkDesc;	// Pointer to the descriptor
	struct _SessDataArea *	ofe_pSda;			// Identifies the owning session
	
	FILESYSHANDLE			ofe_FileSysHandle;	// The file system handles
#define	ofe_ForkHandle		ofe_FileSysHandle.fsh_FileHandle
#define	ofe_pFileObject		ofe_FileSysHandle.fsh_FileObject
#define	ofe_pDeviceObject	ofe_FileSysHandle.fsh_DeviceObject

	DWORD					ofe_OForkRefNum;	// Open Fork reference number
	DWORD					ofe_ForkId;			// Unique file id used by admin.
												// Not re-cycled
	BYTE					ofe_OpenMode;		// Open modes - AFP
	BYTE					ofe_DenyMode;		// Deny modes - AFP
	USHORT					ofe_Flags;			// Flag bits defined above
	LONG					ofe_RefCount;		// Count of references to this entry
	LONG					ofe_cLocks;			// Number of locks on this fork
	KSPIN_LOCK				ofe_Lock;			// Lock for manipulating locks etc.
} OPENFORKENTRY, *POPENFORKENTRY;



#define	RESCFORK(pOpenForkEntry)	\
		(((pOpenForkEntry)->ofe_Flags & OPEN_FORK_RESOURCE) ? True : False)

#define	DATAFORK(pOpenForkEntry)	(!RESCFORK(pOpenForkEntry))

#define	FORK_OPEN_CHUNKS	7
typedef struct _OpenForkSession
{
	POPENFORKENTRY	ofs_pOpenForkEntry[FORK_OPEN_CHUNKS];
										// Pointer to actual entry
	struct _OpenForkSession *ofs_Link;	// Link to next cluster
} OPENFORKSESS, *POPENFORKSESS;

// Used by AfpForkLockOperation call.
typedef	enum
{
	LOCK = 1,
	UNLOCK,
	IOCHECK,
} LOCKOP;

GLOBAL	POPENFORKENTRY	AfpOpenForksList EQU NULL; // List of open forks
GLOBAL	DWORD			AfpNumOpenForks EQU 0;	// Total # of open forks
GLOBAL	KSPIN_LOCK		AfpForksLock EQU { 0 };	// Lock for AfpOpenForksList,
												// and AfpNumOpenForks
extern
NTSTATUS
AfpForksInit(
	VOID
);

extern
POPENFORKENTRY FASTCALL
AfpForkReferenceByRefNum(
	IN	struct _SessDataArea *	pSda,
 	IN	DWORD					OForkRefNum
);

extern
POPENFORKENTRY FASTCALL
AfpForkReferenceByPointer(
	IN	POPENFORKENTRY			pOpenForkEntry
);

extern
POPENFORKENTRY FASTCALL
AfpForkReferenceById(
	IN	DWORD					ForkId
);

extern
VOID FASTCALL
AfpForkDereference(
	IN	POPENFORKENTRY			pOpenForkEntry
);

extern
AFPSTATUS
AfpForkOpen(
	IN	struct _SessDataArea *	pSda,
	IN	struct _ConnDesc *		pConnDesc,
	IN	struct _PathMapEntity *	pPME,
	IN	struct _FileDirParms *	pFDParm,
	IN	DWORD					AccessMode,
	IN	BOOLEAN					Resource,
	OUT	POPENFORKENTRY *		ppOpenForkEntry,
	OUT	PBOOLEAN				pCleanupExchgLock
);

extern
VOID
AfpForkClose(
	IN	POPENFORKENTRY			pOpenForkEntry
);

extern
AFPSTATUS
AfpCheckDenyConflict(
	IN	struct _VolDesc	*		pVolDesc,
	IN	DWORD					AfpId,
	IN	BOOLEAN					Resource,
	IN	BYTE					OpenMode,
	IN	BYTE					DenyMode,
	IN	POPENFORKDESC *			ppOpenForkDesc	OPTIONAL
);

extern
AFPSTATUS
AfpForkLockOperation(
	IN	struct _SessDataArea *	pSda,
	IN	POPENFORKENTRY			pOpenForkEntry,
	IN OUT	PFORKOFFST      	pOffset,
	IN OUT	PFORKSIZE       	pSize,
	IN	LOCKOP					Operation,	// LOCK, UNLOCK or IOCHECK
	IN	BOOLEAN					EndFlag		// If True range is from end, else start
);

extern
VOID
AfpForkLockUnlink(
	IN	PFORKLOCK				pForkLock
);

extern
AFPSTATUS
AfpAdmWForkClose(
	IN	OUT	PVOID	InBuf		OPTIONAL,
	IN	LONG		OutBufLen	OPTIONAL,
	OUT	PVOID		OutBuf		OPTIONAL
);

extern
VOID
AfpExchangeForkAfpIds(
	IN	struct _VolDesc	*		pVolDesc,
	IN	DWORD		AfpId1,
	IN	DWORD		AfpId2
);

#ifdef FORK_LOCALS

LOCAL	DWORD	afpNextForkId = 1;	// Id to be assigned to an open fork

LOCAL BOOLEAN
afpForkGetNewForkRefNumAndLinkInSda(
	IN	struct _SessDataArea *	pSda,
	IN	POPENFORKENTRY			pOpenForkEntry
);

LOCAL
AFPSTATUS
afpForkConvertToAbsOffSize(
	IN	POPENFORKENTRY			pOpenForkEntry,
	IN	LONG					Offset,
	IN OUT	PLONG				pSize,
	OUT	PFORKOFFST				pAbsOffset
);

#endif	// FORK_LOCALS
#endif	// _FORKS_