/*++

Copyright (c) 1989-2000 Microsoft Corporation

Module Name:

    CdProcs.h

Abstract:

    This module defines all of the globally used procedures in the Cdfs
    file system.

// @@BEGIN_DDKSPLIT

Author:

    Brian Andrew    [BrianAn]   01-July-1995

Revision History:

// @@END_DDKSPLIT

--*/

#ifndef _CDPROCS_
#define _CDPROCS_

#include <ntifs.h>

#include <ntddcdrm.h>
#include <ntdddisk.h>
#include <ntddscsi.h>

#include "nodetype.h"
#include "Cd.h"
#include "CdStruc.h"
#include "CdData.h"

//**** x86 compiler bug ****

#if defined(_M_IX86)
#undef Int64ShraMod32
#define Int64ShraMod32(a, b) ((LONGLONG)(a) >> (b))
#endif

//
//  Here are the different pool tags.
//

#define TAG_CCB                 'ccdC'      //  Ccb
#define TAG_CDROM_TOC           'ctdC'      //  TOC
#define TAG_DIRENT_NAME         'nddC'      //  CdName in dirent
#define TAG_ENUM_EXPRESSION     'eedC'      //  Search expression for enumeration
#define TAG_FCB_DATA            'dfdC'      //  Data Fcb
#define TAG_FCB_INDEX           'ifdC'      //  Index Fcb
#define TAG_FCB_NONPAGED        'nfdC'      //  Nonpaged Fcb
#define TAG_FCB_TABLE           'tfdC'      //  Fcb Table entry
#define TAG_FILE_NAME           'nFdC'      //  Filename buffer
#define TAG_GEN_SHORT_NAME      'sgdC'      //  Generated short name
#define TAG_IO_BUFFER           'fbdC'      //  Temporary IO buffer
#define TAG_IO_CONTEXT          'oidC'      //  Io context for async reads
#define TAG_IRP_CONTEXT         'cidC'      //  Irp Context
#define TAG_IRP_CONTEXT_LITE    'lidC'      //  Irp Context lite
#define TAG_MCB_ARRAY           'amdC'      //  Mcb array
#define TAG_PATH_ENTRY_NAME     'nPdC'      //  CdName in path entry
#define TAG_PREFIX_ENTRY        'epdC'      //  Prefix Entry
#define TAG_PREFIX_NAME         'npdC'      //  Prefix Entry name
#define TAG_SPANNING_PATH_TABLE 'psdC'      //  Buffer for spanning path table
#define TAG_UPCASE_NAME         'nudC'      //  Buffer for upcased name
#define TAG_VOL_DESC            'dvdC'      //  Buffer for volume descriptor
#define TAG_VPB                 'pvdC'      //  Vpb allocated in filesystem

//
//  Tag all of our allocations if tagging is turned on
//

#ifdef POOL_TAGGING

#undef FsRtlAllocatePool
#undef FsRtlAllocatePoolWithQuota
#define FsRtlAllocatePool(a,b) FsRtlAllocatePoolWithTag(a,b,'sfdC')
#define FsRtlAllocatePoolWithQuota(a,b) FsRtlAllocatePoolWithQuotaTag(a,b,'sfdC')

#endif // POOL_TAGGING


//
//  File access check routine, implemented in AcChkSup.c
//

//
//  BOOLEAN
//  CdIllegalFcbAccess (
//      IN PIRP_CONTEXT IrpContext,
//      IN TYPE_OF_OPEN TypeOfOpen,
//      IN ACCESS_MASK DesiredAccess
//      );
//

#define CdIllegalFcbAccess(IC,T,DA) (                           \
           BooleanFlagOn( (DA),                                 \
                          ((T) != UserVolumeOpen ?              \
                           (FILE_WRITE_ATTRIBUTES           |   \
                            FILE_WRITE_DATA                 |   \
                            FILE_WRITE_EA                   |   \
                            FILE_ADD_FILE                   |   \
                            FILE_ADD_SUBDIRECTORY           |   \
                            FILE_APPEND_DATA) : 0)          |   \
                          FILE_DELETE_CHILD                 |   \
                          DELETE                            |   \
                          WRITE_DAC ))


//
//  Allocation support routines, implemented in AllocSup.c
//
//  These routines are for querying allocation on individual streams.
//

VOID
CdLookupAllocation (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN LONGLONG FileOffset,
    OUT PLONGLONG DiskOffset,
    OUT PULONG ByteCount
    );

VOID
CdAddAllocationFromDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN ULONG McbEntryOffset,
    IN LONGLONG StartingFileOffset,
    IN PDIRENT Dirent
    );

VOID
CdAddInitialAllocation (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN ULONG StartingBlock,
    IN LONGLONG DataLength
    );

VOID
CdTruncateAllocation (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN LONGLONG StartingFileOffset
    );

VOID
CdInitializeMcb (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb
    );

VOID
CdUninitializeMcb (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb
    );


//
//   Buffer control routines for data caching, implemented in CacheSup.c
//

VOID
CdCreateInternalStream (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN PFCB Fcb
    );

VOID
CdDeleteInternalStream (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb
    );

NTSTATUS
CdCompleteMdl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdPurgeVolume (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN BOOLEAN DismountUnderway
    );

//
//  VOID
//  CdUnpinData (
//      IN PIRP_CONTEXT IrpContext,
//      IN OUT PBCB *Bcb
//      );
//

#define CdUnpinData(IC,B)   \
    if (*(B) != NULL) { CcUnpinData( *(B) ); *(B) = NULL; }


//
//  Device I/O routines, implemented in DevIoSup.c
//
//  These routines perform the actual device read and writes.  They only affect
//  the on disk structure and do not alter any other data structures.
//

NTSTATUS
CdNonCachedRead (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN LONGLONG StartingOffset,
    IN ULONG ByteCount
    );

NTSTATUS
CdNonCachedXARead (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN LONGLONG StartingOffset,
    IN ULONG ByteCount
    );

BOOLEAN
CdReadSectors (
    IN PIRP_CONTEXT IrpContext,
    IN LONGLONG StartingOffset,
    IN ULONG ByteCount,
    IN BOOLEAN RaiseOnError,
    IN OUT PVOID Buffer,
    IN PDEVICE_OBJECT TargetDeviceObject
    );

NTSTATUS
CdCreateUserMdl (
    IN PIRP_CONTEXT IrpContext,
    IN ULONG BufferLength,
    IN BOOLEAN RaiseOnError
    );

NTSTATUS
CdPerformDevIoCtrl (
    IN PIRP_CONTEXT IrpContext,
    IN ULONG IoControlCode,
    IN PDEVICE_OBJECT Device,
    OUT PVOID OutputBuffer OPTIONAL,
    IN ULONG OutputBufferLength,
    IN BOOLEAN InternalDeviceIoControl,
    IN BOOLEAN OverrideVerify,
    OUT PIO_STATUS_BLOCK Iosb OPTIONAL
    );

//
//  VOID
//  CdMapUserBuffer (
//      IN PIRP_CONTEXT IrpContext
//      OUT PVOID UserBuffer
//      );
//
//  Returns pointer to sys address.  Will raise on failure.
//
//
//  VOID
//  CdLockUserBuffer (
//      IN PIRP_CONTEXT IrpContext,
//      IN ULONG BufferLength
//      );
//

#define CdMapUserBuffer(IC, UB) {                                               \
            *(UB) = (PVOID) ( ((IC)->Irp->MdlAddress == NULL) ?                 \
                    (IC)->Irp->UserBuffer :                                     \
                    (MmGetSystemAddressForMdlSafe( (IC)->Irp->MdlAddress, NormalPagePriority)));   \
            if (NULL == *(UB))  {                         \
                CdRaiseStatus( (IC), STATUS_INSUFFICIENT_RESOURCES);            \
            }                                                                   \
        }                                                                       
        

#define CdLockUserBuffer(IC,BL) {                   \
    if ((IC)->Irp->MdlAddress == NULL) {            \
        (VOID) CdCreateUserMdl( (IC), (BL), TRUE ); \
    }                                               \
}


//
//  Dirent support routines, implemented in DirSup.c
//

VOID
CdLookupDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN ULONG DirentOffset,
    OUT PDIRENT_ENUM_CONTEXT DirContext
    );

BOOLEAN
CdLookupNextDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PDIRENT_ENUM_CONTEXT CurrentDirContext,
    OUT PDIRENT_ENUM_CONTEXT NextDirContext
    );

VOID
CdUpdateDirentFromRawDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PDIRENT_ENUM_CONTEXT DirContext,
    IN OUT PDIRENT Dirent
    );

VOID
CdUpdateDirentName (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PDIRENT Dirent,
    IN ULONG IgnoreCase
    );

BOOLEAN
CdFindFile (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PCD_NAME Name,
    IN BOOLEAN IgnoreCase,
    IN OUT PFILE_ENUM_CONTEXT FileContext,
    OUT PCD_NAME *MatchingName
    );

BOOLEAN
CdFindDirectory (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PCD_NAME Name,
    IN BOOLEAN IgnoreCase,
    IN OUT PFILE_ENUM_CONTEXT FileContext
    );

BOOLEAN
CdFindFileByShortName (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PCD_NAME Name,
    IN BOOLEAN IgnoreCase,
    IN ULONG ShortNameDirentOffset,
    IN OUT PFILE_ENUM_CONTEXT FileContext
    );

BOOLEAN
CdLookupNextInitialFileDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN OUT PFILE_ENUM_CONTEXT FileContext
    );

VOID
CdLookupLastFileDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PFILE_ENUM_CONTEXT FileContext
    );

VOID
CdCleanupFileContext (
    IN PIRP_CONTEXT IrpContext,
    IN PFILE_ENUM_CONTEXT FileContext
    );

//
//  VOID
//  CdInitializeFileContext (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFILE_ENUM_CONTEXT FileContext
//      );
//
//
//  VOID
//  CdInitializeDirent (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDIRENT Dirent
//      );
//
//  VOID
//  CdInitializeDirContext (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDIRENT_ENUM_CONTEXT DirContext
//      );
//
//  VOID
//  CdCleanupDirent (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDIRENT Dirent
//      );
//
//  VOID
//  CdCleanupDirContext (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDIRENT_ENUM_CONTEXT DirContext
//      );
//
//  VOID
//  CdLookupInitialFileDirent (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb,
//      IN PFILE_ENUM_CONTEXT FileContext,
//      IN ULONG DirentOffset
//      );
//

#define CdInitializeFileContext(IC,FC) {                                \
    RtlZeroMemory( FC, sizeof( FILE_ENUM_CONTEXT ));                    \
    (FC)->PriorDirent = &(FC)->Dirents[0];                              \
    (FC)->InitialDirent = &(FC)->Dirents[1];                            \
    (FC)->CurrentDirent = &(FC)->Dirents[2];                            \
    (FC)->ShortName.FileName.MaximumLength = BYTE_COUNT_8_DOT_3;        \
    (FC)->ShortName.FileName.Buffer = (FC)->ShortNameBuffer;            \
}

#define CdInitializeDirent(IC,D)                                \
    RtlZeroMemory( D, sizeof( DIRENT ))

#define CdInitializeDirContext(IC,DC)                           \
    RtlZeroMemory( DC, sizeof( DIRENT_ENUM_CONTEXT ))

#define CdCleanupDirent(IC,D)  {                                \
    if (FlagOn( (D)->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {       \
        ExFreePool( (D)->CdFileName.FileName.Buffer );          \
    }                                                           \
}

#define CdCleanupDirContext(IC,DC)                              \
    CdUnpinData( (IC), &(DC)->Bcb )

#define CdLookupInitialFileDirent(IC,F,FC,DO)                       \
    CdLookupDirent( IC,                                             \
                    F,                                              \
                    DO,                                             \
                    &(FC)->InitialDirent->DirContext );             \
    CdUpdateDirentFromRawDirent( IC,                                \
                                 F,                                 \
                                 &(FC)->InitialDirent->DirContext,  \
                                 &(FC)->InitialDirent->Dirent )


//
//  The following routines are used to manipulate the fscontext fields
//  of the file object, implemented in FilObSup.c
//

//
//  Type of opens.  FilObSup.c depends on this order.
//

typedef enum _TYPE_OF_OPEN {

    UnopenedFileObject = 0,
    StreamFileOpen,
    UserVolumeOpen,
    UserDirectoryOpen,
    UserFileOpen,
    BeyondValidType

} TYPE_OF_OPEN;
typedef TYPE_OF_OPEN *PTYPE_OF_OPEN;

VOID
CdSetFileObject (
    IN PIRP_CONTEXT IrpContext,
    IN PFILE_OBJECT FileObject,
    IN TYPE_OF_OPEN TypeOfOpen,
    IN PFCB Fcb OPTIONAL,
    IN PCCB Ccb OPTIONAL
    );

TYPE_OF_OPEN
CdDecodeFileObject (
    IN PIRP_CONTEXT IrpContext,
    IN PFILE_OBJECT FileObject,
    OUT PFCB *Fcb,
    OUT PCCB *Ccb
    );

TYPE_OF_OPEN
CdFastDecodeFileObject (
    IN PFILE_OBJECT FileObject,
    OUT PFCB *Fcb
    );


//
//  Name support routines, implemented in NameSup.c
//

VOID
CdConvertNameToCdName (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PCD_NAME CdName
    );

VOID
CdConvertBigToLittleEndian (
    IN PIRP_CONTEXT IrpContext,
    IN PCHAR BigEndian,
    IN ULONG ByteCount,
    OUT PCHAR LittleEndian
    );

VOID
CdUpcaseName (
    IN PIRP_CONTEXT IrpContext,
    IN PCD_NAME Name,
    IN OUT PCD_NAME UpcaseName
    );

VOID
CdDissectName (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PUNICODE_STRING RemainingName,
    OUT PUNICODE_STRING FinalName
    );

BOOLEAN
CdIs8dot3Name (
    IN PIRP_CONTEXT IrpContext,
    IN UNICODE_STRING FileName
    );

VOID
CdGenerate8dot3Name (
    IN PIRP_CONTEXT IrpContext,
    IN PUNICODE_STRING FileName,
    IN ULONG DirentOffset,
    OUT PWCHAR ShortFileName,
    OUT PUSHORT ShortByteCount
    );

BOOLEAN
CdIsNameInExpression (
    IN PIRP_CONTEXT IrpContext,
    IN PCD_NAME CurrentName,
    IN PCD_NAME SearchExpression,
    IN ULONG  WildcardFlags,
    IN BOOLEAN CheckVersion
    );

ULONG
CdShortNameDirentOffset (
    IN PIRP_CONTEXT IrpContext,
    IN PUNICODE_STRING Name
    );

FSRTL_COMPARISON_RESULT
CdFullCompareNames (
    IN PIRP_CONTEXT IrpContext,
    IN PUNICODE_STRING NameA,
    IN PUNICODE_STRING NameB
    );


//
//  Filesystem control operations.  Implemented in Fsctrl.c
//

NTSTATUS
CdLockVolumeInternal (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN PFILE_OBJECT FileObject OPTIONAL
    );

NTSTATUS
CdUnlockVolumeInternal (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN PFILE_OBJECT FileObject OPTIONAL
    );


//
//  Path table enumeration routines.  Implemented in PathSup.c
//

VOID
CdLookupPathEntry (
    IN PIRP_CONTEXT IrpContext,
    IN ULONG PathEntryOffset,
    IN ULONG Ordinal,
    IN BOOLEAN VerifyBounds,
    IN OUT PCOMPOUND_PATH_ENTRY CompoundPathEntry
    );

BOOLEAN
CdLookupNextPathEntry (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PPATH_ENUM_CONTEXT PathContext,
    IN OUT PPATH_ENTRY PathEntry
    );

BOOLEAN
CdFindPathEntry (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB ParentFcb,
    IN PCD_NAME DirName,
    IN BOOLEAN IgnoreCase,
    IN OUT PCOMPOUND_PATH_ENTRY CompoundPathEntry
    );

VOID
CdUpdatePathEntryName (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PPATH_ENTRY PathEntry,
    IN BOOLEAN IgnoreCase
    );

//
//  VOID
//  CdInitializeCompoundPathEntry (
//      IN PIRP_CONTEXT IrpContext,
//      IN PCOMPOUND_PATH_ENTRY CompoundPathEntry
//      );
//
//  VOID
//  CdCleanupCompoundPathEntry (
//      IN PIRP_CONTEXT IrpContext,
//      IN PCOMPOUND_PATH_ENTRY CompoundPathEntry
//      );
//

#define CdInitializeCompoundPathEntry(IC,CP)                                    \
    RtlZeroMemory( CP, sizeof( COMPOUND_PATH_ENTRY ))

#define CdCleanupCompoundPathEntry(IC,CP)     {                                 \
    CdUnpinData( (IC), &(CP)->PathContext.Bcb );                                \
    if ((CP)->PathContext.AllocatedData) {                                      \
        ExFreePool( (CP)->PathContext.Data );                                   \
    }                                                                           \
    if (FlagOn( (CP)->PathEntry.Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER )) {        \
        ExFreePool( (CP)->PathEntry.CdDirName.FileName.Buffer );                \
    }                                                                           \
}


//
//  Largest matching prefix searching routines, implemented in PrefxSup.c
//

VOID
CdInsertPrefix (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PCD_NAME Name,
    IN BOOLEAN IgnoreCase,
    IN BOOLEAN ShortNameMatch,
    IN PFCB ParentFcb
    );

VOID
CdRemovePrefix (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb
    );

VOID
CdFindPrefix (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PFCB *CurrentFcb,
    IN OUT PUNICODE_STRING RemainingName,
    IN BOOLEAN IgnoreCase
    );


//
//  Synchronization routines.  Implemented in Resrcsup.c
//
//  The following routines/macros are used to synchronize the in-memory structures.
//
//      Routine/Macro               Synchronizes                            Subsequent
//
//      CdAcquireCdData             Volume Mounts/Dismounts,Vcb Queue       CdReleaseCdData
//      CdAcquireVcbExclusive       Vcb for open/close                      CdReleaseVcb
//      CdAcquireVcbShared          Vcb for open/close                      CdReleaseVcb
//      CdAcquireAllFiles           Locks out operations to all files       CdReleaseAllFiles
//      CdAcquireFileExclusive      Locks out file operations               CdReleaseFile
//      CdAcquireFileShared         Files for file operations               CdReleaseFile
//      CdAcquireFcbExclusive       Fcb for open/close                      CdReleaseFcb
//      CdAcquireFcbShared          Fcb for open/close                      CdReleaseFcb
//      CdLockCdData                Fields in CdData                        CdUnlockCdData
//      CdLockVcb                   Vcb fields, FcbReference, FcbTable      CdUnlockVcb
//      CdLockFcb                   Fcb fields, prefix table, Mcb           CdUnlockFcb
//

typedef enum _TYPE_OF_ACQUIRE {
    
    AcquireExclusive,
    AcquireShared,
    AcquireSharedStarveExclusive

} TYPE_OF_ACQUIRE, *PTYPE_OF_ACQUIRE;

BOOLEAN
CdAcquireResource (
    IN PIRP_CONTEXT IrpContext,
    IN PERESOURCE Resource,
    IN BOOLEAN IgnoreWait,
    IN TYPE_OF_ACQUIRE Type
    );

//
//  BOOLEAN
//  CdAcquireCdData (
//      IN PIRP_CONTEXT IrpContext
//      );
//
//  VOID
//  CdReleaseCdData (
//      IN PIRP_CONTEXT IrpContext
//    );
//
//  BOOLEAN
//  CdAcquireVcbExclusive (
//      IN PIRP_CONTEXT IrpContext,
//      IN PVCB Vcb,
//      IN BOOLEAN IgnoreWait
//      );
//
//  BOOLEAN
//  CdAcquireVcbShared (
//      IN PIRP_CONTEXT IrpContext,
//      IN PVCB Vcb,
//      IN BOOLEAN IgnoreWait
//      );
//
//  VOID
//  CdReleaseVcb (
//      IN PIRP_CONTEXT IrpContext,
//      IN PVCB Vcb
//      );
//
//  VOID
//  CdAcquireAllFiles (
//      IN PIRP_CONTEXT,
//      IN PVCB Vcb
//      );
//
//  VOID
//  CdReleaseAllFiles (
//      IN PIRP_CONTEXT,
//      IN PVCB Vcb
//      );
//
//  VOID
//  CdAcquireFileExclusive (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb,
//      );
//
//  VOID
//  CdAcquireFileShared (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//
//  VOID
//  CdReleaseFile (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//    );
//
//  BOOLEAN
//  CdAcquireFcbExclusive (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb,
//      IN BOOLEAN IgnoreWait
//      );
//
//  BOOLEAN
//  CdAcquireFcbShared (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb,
//      IN BOOLEAN IgnoreWait
//      );
//
//  BOOLEAN
//  CdReleaseFcb (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//
//  VOID
//  CdLockCdData (
//      );
//
//  VOID
//  CdUnlockCdData (
//      );
//
//  VOID
//  CdLockVcb (
//      IN PIRP_CONTEXT IrpContext
//      );
//
//  VOID
//  CdUnlockVcb (
//      IN PIRP_CONTEXT IrpContext
//      );
//
//  VOID
//  CdLockFcb (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//
//  VOID
//  CdUnlockFcb (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//

#define CdAcquireCdData(IC)                                                             \
    ExAcquireResourceExclusiveLite( &CdData.DataResource, TRUE )

#define CdReleaseCdData(IC)                                                             \
    ExReleaseResourceLite( &CdData.DataResource )

#define CdAcquireVcbExclusive(IC,V,I)                                                   \
    CdAcquireResource( (IC), &(V)->VcbResource, (I), AcquireExclusive )

#define CdAcquireVcbShared(IC,V,I)                                                      \
    CdAcquireResource( (IC), &(V)->VcbResource, (I), AcquireShared )

#define CdReleaseVcb(IC,V)                                                              \
    ExReleaseResourceLite( &(V)->VcbResource )

#define CdAcquireAllFiles(IC,V)                                                         \
    CdAcquireResource( (IC), &(V)->FileResource, FALSE, AcquireExclusive )

#define CdReleaseAllFiles(IC,V)                                                         \
    ExReleaseResourceLite( &(V)->FileResource )

#define CdAcquireFileExclusive(IC,F)                                                    \
    CdAcquireResource( (IC), (F)->Resource, FALSE, AcquireExclusive )

#define CdAcquireFileShared(IC,F)                                                       \
    CdAcquireResource( (IC), (F)->Resource, FALSE, AcquireShared )

#define CdAcquireFileSharedStarveExclusive(IC,F)                                        \
    CdAcquireResource( (IC), (F)->Resource, FALSE, AcquireSharedStarveExclusive )

#define CdReleaseFile(IC,F)                                                             \
    ExReleaseResourceLite( (F)->Resource )

#define CdAcquireFcbExclusive(IC,F,I)                                                   \
    CdAcquireResource( (IC), &(F)->FcbNonpaged->FcbResource, (I), AcquireExclusive )

#define CdAcquireFcbShared(IC,F,I)                                                      \
    CdAcquireResource( (IC), &(F)->FcbNonpaged->FcbResource, (I), AcquireShared )

#define CdReleaseFcb(IC,F)                                                              \
    ExReleaseResourceLite( &(F)->FcbNonpaged->FcbResource )

#define CdLockCdData()                                                                  \
    ExAcquireFastMutex( &CdData.CdDataMutex );                                          \
    CdData.CdDataLockThread = PsGetCurrentThread()

#define CdUnlockCdData()                                                                \
    CdData.CdDataLockThread = NULL;                                                     \
    ExReleaseFastMutex( &CdData.CdDataMutex )

#define CdLockVcb(IC,V)                                                                 \
    ExAcquireFastMutex( &(V)->VcbMutex );                                               \
    ASSERT( NULL == (V)->VcbLockThread);                                                \
    (V)->VcbLockThread = PsGetCurrentThread()

#define CdUnlockVcb(IC,V)                                                               \
    ASSERT( NULL != (V)->VcbLockThread);                                                \
    (V)->VcbLockThread = NULL;                                                          \
    ExReleaseFastMutex( &(V)->VcbMutex )

#define CdLockFcb(IC,F) {                                                               \
    PVOID _CurrentThread = PsGetCurrentThread();                                        \
    if (_CurrentThread != (F)->FcbLockThread) {                                         \
        ExAcquireFastMutex( &(F)->FcbNonpaged->FcbMutex );                              \
        ASSERT( (F)->FcbLockCount == 0 );                                               \
        (F)->FcbLockThread = _CurrentThread;                                            \
    }                                                                                   \
    (F)->FcbLockCount += 1;                                                             \
}

#define CdUnlockFcb(IC,F) {                                                             \
    (F)->FcbLockCount -= 1;                                                             \
    if ((F)->FcbLockCount == 0) {                                                       \
        (F)->FcbLockThread = NULL;                                                      \
        ExReleaseFastMutex( &(F)->FcbNonpaged->FcbMutex );                              \
    }                                                                                   \
}

BOOLEAN
CdNoopAcquire (
    IN PVOID Fcb,
    IN BOOLEAN Wait
    );

VOID
CdNoopRelease (
    IN PVOID Fcb
    );

BOOLEAN
CdAcquireForCache (
    IN PFCB Fcb,
    IN BOOLEAN Wait
    );

VOID
CdReleaseFromCache (
    IN PFCB Fcb
    );

VOID
CdAcquireForCreateSection (
    IN PFILE_OBJECT FileObject
    );

VOID
CdReleaseForCreateSection (
    IN PFILE_OBJECT FileObject
    );


//
//  In-memory structure support routines.  Implemented in StrucSup.c
//

VOID
CdInitializeVcb (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PVCB Vcb,
    IN PDEVICE_OBJECT TargetDeviceObject,
    IN PVPB Vpb,
    IN PCDROM_TOC CdromToc,
    IN ULONG TocLength,
    IN ULONG TocTrackCount,
    IN ULONG TocDiskFlags,
    IN ULONG BlockFactor,
    IN ULONG MediaChangeCount
    );

VOID
CdUpdateVcbFromVolDescriptor (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PVCB Vcb,
    IN PCHAR RawIsoVd OPTIONAL
    );

VOID
CdDeleteVcb (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PVCB Vcb
    );

PFCB
CdCreateFcb (
    IN PIRP_CONTEXT IrpContext,
    IN FILE_ID FileId,
    IN NODE_TYPE_CODE NodeTypeCode,
    OUT PBOOLEAN FcbExisted OPTIONAL
    );

VOID
CdInitializeFcbFromPathEntry (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PFCB ParentFcb OPTIONAL,
    IN PPATH_ENTRY PathEntry
    );

VOID
CdInitializeFcbFromFileContext (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PFCB ParentFcb OPTIONAL,
    IN PFILE_ENUM_CONTEXT FileContext
    );

PCCB
CdCreateCcb (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN ULONG Flags
    );

VOID
CdDeleteCcb (
    IN PIRP_CONTEXT IrpContext,
    IN PCCB Ccb
    );

BOOLEAN
CdCreateFileLock (
    IN PIRP_CONTEXT IrpContext OPTIONAL,
    IN PFCB Fcb,
    IN BOOLEAN RaiseOnError
    );

VOID
CdDeleteFileLock (
    IN PIRP_CONTEXT IrpContext,
    IN PFILE_LOCK FileLock
    );

PIRP_CONTEXT
CdCreateIrpContext (
    IN PIRP Irp,
    IN BOOLEAN Wait
    );

VOID
CdCleanupIrpContext (
    IN PIRP_CONTEXT IrpContext,
    IN BOOLEAN Post
    );

VOID
CdInitializeStackIrpContext (
    OUT PIRP_CONTEXT IrpContext,
    IN PIRP_CONTEXT_LITE IrpContextLite
    );

//
//  PIRP_CONTEXT_LITE
//  CdCreateIrpContextLite (
//      IN PIRP_CONTEXT IrpContext
//      );
//
//  VOID
//  CdFreeIrpContextLite (
//      IN PIRP_CONTEXT_LITE IrpContextLite
//      );
//

#define CdCreateIrpContextLite(IC)  \
    ExAllocatePoolWithTag( CdNonPagedPool, sizeof( IRP_CONTEXT_LITE ), TAG_IRP_CONTEXT_LITE )

#define CdFreeIrpContextLite(ICL)  \
    ExFreePool( ICL )

VOID
CdTeardownStructures (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB StartingFcb,
    OUT PBOOLEAN RemovedStartingFcb
    );

//
//  VOID
//  CdIncrementCleanupCounts (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//
//  VOID
//  CdDecrementCleanupCounts (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//
//  VOID
//  CdIncrementReferenceCounts (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb,
//      IN ULONG ReferenceCount
//      IN ULONG UserReferenceCount
//      );
//
//  VOID
//  CdDecrementReferenceCounts (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb,
//      IN ULONG ReferenceCount
//      IN ULONG UserReferenceCount
//      );
//
//  VOID
//  CdIncrementFcbReference (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//
//  VOID
//  CdDecrementFcbReference (
//      IN PIRP_CONTEXT IrpContext,
//      IN PFCB Fcb
//      );
//

#define CdIncrementCleanupCounts(IC,F) {        \
    ASSERT_LOCKED_VCB( (F)->Vcb );              \
    (F)->FcbCleanup += 1;                       \
    (F)->Vcb->VcbCleanup += 1;                  \
}

#define CdDecrementCleanupCounts(IC,F) {        \
    ASSERT_LOCKED_VCB( (F)->Vcb );              \
    (F)->FcbCleanup -= 1;                       \
    (F)->Vcb->VcbCleanup -= 1;                  \
}

#define CdIncrementReferenceCounts(IC,F,C,UC) { \
    ASSERT_LOCKED_VCB( (F)->Vcb );              \
    (F)->FcbReference += (C);                   \
    (F)->FcbUserReference += (UC);              \
    (F)->Vcb->VcbReference += (C);              \
    (F)->Vcb->VcbUserReference += (UC);         \
}

#define CdDecrementReferenceCounts(IC,F,C,UC) { \
    ASSERT_LOCKED_VCB( (F)->Vcb );              \
    (F)->FcbReference -= (C);                   \
    (F)->FcbUserReference -= (UC);              \
    (F)->Vcb->VcbReference -= (C);              \
    (F)->Vcb->VcbUserReference -= (UC);         \
}

//
//  PCD_IO_CONTEXT
//  CdAllocateIoContext (
//      );
//
//  VOID
//  CdFreeIoContext (
//      PCD_IO_CONTEXT IoContext
//      );
//

#define CdAllocateIoContext()                           \
    FsRtlAllocatePoolWithTag( CdNonPagedPool,           \
                              sizeof( CD_IO_CONTEXT ),  \
                              TAG_IO_CONTEXT )

#define CdFreeIoContext(IO)     ExFreePool( IO )

PFCB
CdLookupFcbTable (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN FILE_ID FileId
    );

PFCB
CdGetNextFcb (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN PVOID *RestartKey
    );

NTSTATUS
CdProcessToc (
    IN PIRP_CONTEXT IrpContext,
    IN PDEVICE_OBJECT TargetDeviceObject,
    IN PCDROM_TOC CdromToc,
    IN OUT PULONG Length,
    OUT PULONG TrackCount,
    OUT PULONG DiskFlags
    );

//
//  For debugging purposes we sometimes want to allocate our structures from nonpaged
//  pool so that in the kernel debugger we can walk all the structures.
//

#define CdPagedPool                 PagedPool
#define CdNonPagedPool              NonPagedPool
#define CdNonPagedPoolCacheAligned  NonPagedPoolCacheAligned


//
//  Verification support routines.  Contained in verfysup.c
//

NTSTATUS
CdPerformVerify (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp,
    IN PDEVICE_OBJECT DeviceToVerify
    );

BOOLEAN
CdCheckForDismount (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB,
    IN BOOLEAN Force
    );

VOID
CdVerifyVcb (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb
    );

BOOLEAN
CdVerifyFcbOperation (
    IN PIRP_CONTEXT IrpContext OPTIONAL,
    IN PFCB Fcb
    );

BOOLEAN
CdDismountVcb (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb
    );

//
//  Macros to abstract device verify flag changes.
//

#define CdUpdateMediaChangeCount( V, C)  (V)->MediaChangeCount = (C)
#define CdUpdateVcbCondition( V, C)      (V)->VcbCondition = (C)

#define CdMarkRealDevForVerify( DO)  SetFlag( (DO)->Flags, DO_VERIFY_VOLUME)
#define CdMarkRealDevVerifyOk( DO)   ClearFlag( (DO)->Flags, DO_VERIFY_VOLUME)

#define CdRealDevNeedsVerify( DO)    BooleanFlagOn( (DO)->Flags, DO_VERIFY_VOLUME)

//
//  BOOLEAN
//  CdIsRawDevice (
//      IN PIRP_CONTEXT IrpContext,
//      IN NTSTATUS Status
//      );
//

#define CdIsRawDevice(IC,S) (           \
    ((S) == STATUS_DEVICE_NOT_READY) || \
    ((S) == STATUS_NO_MEDIA_IN_DEVICE)  \
)


//
//  Work queue routines for posting and retrieving an Irp, implemented in
//  workque.c
//

NTSTATUS
CdFsdPostRequest(
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

VOID
CdPrePostIrp (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

VOID
CdOplockComplete (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );


//
//  Miscellaneous support routines
//

//
//  This macro returns TRUE if a flag in a set of flags is on and FALSE
//  otherwise
//

//#ifndef BooleanFlagOn
//#define BooleanFlagOn(F,SF) (    \
//    (BOOLEAN)(((F) & (SF)) != 0) \
//)
//#endif

//#ifndef SetFlag
//#define SetFlag(Flags,SingleFlag) { \
//    (Flags) |= (SingleFlag);        \
//}
//#endif

//#ifndef ClearFlag
//#define ClearFlag(Flags,SingleFlag) { \
//    (Flags) &= ~(SingleFlag);         \
//}
//#endif

//
//      CAST
//      Add2Ptr (
//          IN PVOID Pointer,
//          IN ULONG Increment
//          IN (CAST)
//          );
//
//      ULONG
//      PtrOffset (
//          IN PVOID BasePtr,
//          IN PVOID OffsetPtr
//          );
//

#define Add2Ptr(PTR,INC,CAST) ((CAST)((PUCHAR)(PTR) + (INC)))

#define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG_PTR)(OFFSET) - (ULONG_PTR)(BASE)))

//
//  This macro takes a pointer (or ulong) and returns its rounded up word
//  value
//

#define WordAlign(Ptr) (                \
    ((((ULONG)(Ptr)) + 1) & 0xfffffffe) \
    )

//
//  This macro takes a pointer (or ulong) and returns its rounded up longword
//  value
//

#define LongAlign(Ptr) (                \
    ((((ULONG)(Ptr)) + 3) & 0xfffffffc) \
    )

//
//  This macro takes a pointer (or ulong) and returns its rounded up quadword
//  value
//

#define QuadAlign(Ptr) (                \
    ((((ULONG)(Ptr)) + 7) & 0xfffffff8) \
    )

//
//  The following macros round up and down to sector boundaries.
//

#define SectorAlign(L) (                                                \
    ((((ULONG)(L)) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))           \
)

#define LlSectorAlign(L) (                                              \
    ((((LONGLONG)(L)) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))        \
)

#define SectorTruncate(L) (                                             \
    ((ULONG)(L)) & ~(SECTOR_SIZE - 1)                                   \
)

#define LlSectorTruncate(L) (                                           \
    ((LONGLONG)(L)) & ~(SECTOR_SIZE - 1)                                \
)

#define BytesFromSectors(L) (                                           \
    ((ULONG) (L)) << SECTOR_SHIFT                                       \
)

#define SectorsFromBytes(L) (                                           \
    ((ULONG) (L)) >> SECTOR_SHIFT                                       \
)

#define LlBytesFromSectors(L) (                                         \
    Int64ShllMod32( (LONGLONG)(L), SECTOR_SHIFT )                       \
)

#define LlSectorsFromBytes(L) (                                         \
    Int64ShraMod32( (LONGLONG)(L), SECTOR_SHIFT )                       \
)

#define SectorOffset(L) (                                               \
    ((ULONG)(ULONG_PTR) (L)) & SECTOR_MASK                              \
)

#define SectorBlockOffset(V,LB) (                                       \
    ((ULONG) (LB)) & ((V)->BlocksPerSector - 1)                         \
)

#define BytesFromBlocks(V,B) (                                          \
    (ULONG) (B) << (V)->BlockToByteShift                                \
)

#define LlBytesFromBlocks(V,B) (                                        \
    Int64ShllMod32( (LONGLONG) (B), (V)->BlockToByteShift )             \
)

#define BlockAlign(V,L) (                                               \
    ((ULONG)(L) + (V)->BlockMask) & (V)->BlockInverseMask               \
)

//
//  Carefully make sure the mask is sign extended to 64bits
//

#define LlBlockAlign(V,L) (                                                     \
    ((LONGLONG)(L) + (V)->BlockMask) & (LONGLONG)((LONG)(V)->BlockInverseMask)  \
)

#define BlockOffset(V,L) (                                              \
    ((ULONG) (L)) & (V)->BlockMask                                      \
)

#define RawSectorAlign( B) ((((B)+(RAW_SECTOR_SIZE - 1)) / RAW_SECTOR_SIZE) * RAW_SECTOR_SIZE)

//
//  The following types and macros are used to help unpack the packed and
//  misaligned fields found in the Bios parameter block
//

typedef union _UCHAR1 {
    UCHAR  Uchar[1];
    UCHAR  ForceAlignment;
} UCHAR1, *PUCHAR1;

typedef union _UCHAR2 {
    UCHAR  Uchar[2];
    USHORT ForceAlignment;
} UCHAR2, *PUCHAR2;

typedef union _UCHAR4 {
    UCHAR  Uchar[4];
    ULONG  ForceAlignment;
} UCHAR4, *PUCHAR4;

typedef union _USHORT2 {
    USHORT Ushort[2];
    ULONG  ForceAlignment;
} USHORT2, *PUSHORT2;

//
//  This macro copies an unaligned src byte to an aligned dst byte
//

#define CopyUchar1(Dst,Src) {                           \
    *((UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src));  \
    }

//
//  This macro copies an unaligned src word to an aligned dst word
//

#define CopyUchar2(Dst,Src) {                           \
    *((UCHAR2 *)(Dst)) = *((UNALIGNED UCHAR2 *)(Src));  \
    }

//
//  This macro copies an unaligned src longword to an aligned dsr longword
//

#define CopyUchar4(Dst,Src) {                           \
    *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src));  \
    }

//
//  This macro copies an unaligned src longword to an aligned dsr longword
//  accessing the source on a word boundary.
//

#define CopyUshort2(Dst,Src) {                          \
    *((USHORT2 *)(Dst)) = *((UNALIGNED USHORT2 *)(Src));\
    }


//
//  Following routines handle entry in and out of the filesystem.  They are
//  contained in CdData.c
//

NTSTATUS
CdFsdDispatch (
    IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
    IN PIRP Irp
    );

LONG
CdExceptionFilter (
    IN PIRP_CONTEXT IrpContext,
    IN PEXCEPTION_POINTERS ExceptionPointer
    );

NTSTATUS
CdProcessException (
    IN PIRP_CONTEXT IrpContext OPTIONAL,
    IN PIRP Irp,
    IN NTSTATUS ExceptionCode
    );

VOID
CdCompleteRequest (
    IN PIRP_CONTEXT IrpContext OPTIONAL,
    IN PIRP Irp OPTIONAL,
    IN NTSTATUS Status
    );

//
//  VOID
//  CdRaiseStatus (
//      IN PRIP_CONTEXT IrpContext,
//      IN NT_STATUS Status
//      );
//
//  VOID
//  CdNormalAndRaiseStatus (
//      IN PRIP_CONTEXT IrpContext,
//      IN NT_STATUS Status
//      );
//

#if 0
#define AssertVerifyDevice(C, S)                                                    \
    ASSERT( (C) == NULL ||                                                          \
            FlagOn( (C)->Flags, IRP_CONTEXT_FLAG_IN_FSP ) ||                        \
            !((S) == STATUS_VERIFY_REQUIRED &&                                      \
              IoGetDeviceToVerify( PsGetCurrentThread() ) == NULL ));

#define AssertVerifyDeviceIrp(I)                                                    \
    ASSERT( (I) == NULL ||                                                          \
            !(((I)->IoStatus.Status) == STATUS_VERIFY_REQUIRED &&                   \
              ((I)->Tail.Overlay.Thread == NULL ||                                  \
                IoGetDeviceToVerify( (I)->Tail.Overlay.Thread ) == NULL )));
#else
#define AssertVerifyDevice(C, S)
#define AssertVerifyDeviceIrp(I)
#endif

#define CdRaiseStatus(IC,S) {                               \
    AssertVerifyDevice(IC, S);                              \
    (IC)->ExceptionStatus = (S);                            \
    DebugBreakOnStatus( S );                                \
    ExRaiseStatus( (S) );                                   \
}

#define CdNormalizeAndRaiseStatus(IC,S) {                                           \
    AssertVerifyDevice(IC, S);                                                      \
    (IC)->ExceptionStatus = FsRtlNormalizeNtstatus((S),STATUS_UNEXPECTED_IO_ERROR); \
    ExRaiseStatus( (IC)->ExceptionStatus );                                         \
}

//
//  Following are the fast entry points.
//

BOOLEAN
CdFastQueryBasicInfo (
    IN PFILE_OBJECT FileObject,
    IN BOOLEAN Wait,
    IN OUT PFILE_BASIC_INFORMATION Buffer,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
CdFastQueryStdInfo (
    IN PFILE_OBJECT FileObject,
    IN BOOLEAN Wait,
    IN OUT PFILE_STANDARD_INFORMATION Buffer,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
CdFastLock (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN PLARGE_INTEGER Length,
    PEPROCESS ProcessId,
    ULONG Key,
    BOOLEAN FailImmediately,
    BOOLEAN ExclusiveLock,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
CdFastUnlockSingle (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN PLARGE_INTEGER Length,
    PEPROCESS ProcessId,
    ULONG Key,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
CdFastUnlockAll (
    IN PFILE_OBJECT FileObject,
    PEPROCESS ProcessId,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
CdFastUnlockAllByKey (
    IN PFILE_OBJECT FileObject,
    PVOID ProcessId,
    ULONG Key,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
CdFastIoCheckIfPossible (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN ULONG Length,
    IN BOOLEAN Wait,
    IN ULONG LockKey,
    IN BOOLEAN CheckForReadOperation,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
CdFastQueryNetworkInfo (
    IN PFILE_OBJECT FileObject,
    IN BOOLEAN Wait,
    OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    );

//
//  Following are the routines to handle the top level thread logic.
//

VOID
CdSetThreadContext (
    IN PIRP_CONTEXT IrpContext,
    IN PTHREAD_CONTEXT ThreadContext
    );

//
//  VOID
//  CdRestoreThreadContext (
//      IN PIRP_CONTEXT IrpContext
//      );
//

#define CdRestoreThreadContext(IC)                              \
    (IC)->ThreadContext->Cdfs = 0;                              \
    IoSetTopLevelIrp( (IC)->ThreadContext->SavedTopLevelIrp );  \
    (IC)->ThreadContext = NULL

ULONG
CdSerial32 (
    IN PCHAR Buffer,
    IN ULONG ByteCount
    );

//
//  The following macro is used to determine if an FSD thread can block
//  for I/O or wait for a resource.  It returns TRUE if the thread can
//  block and FALSE otherwise.  This attribute can then be used to call
//  the FSD & FSP common work routine with the proper wait value.
//

#define CanFsdWait(I)   IoIsOperationSynchronous(I)

//
//  The following macro is used to set the fast i/o possible bits in the
//  FsRtl header.
//
//      FastIoIsNotPossible - If the Fcb is bad or there are oplocks on the file.
//
//      FastIoIsQuestionable - If there are file locks.
//
//      FastIoIsPossible - In all other cases.
//
//

#define CdIsFastIoPossible(F) ((BOOLEAN)                                            \
    ((((F)->Vcb->VcbCondition != VcbMounted ) ||                                    \
      !FsRtlOplockIsFastIoPossible( &(F)->Oplock )) ?                               \
                                                                                    \
     FastIoIsNotPossible :                                                          \
                                                                                    \
     ((((F)->FileLock != NULL) && FsRtlAreThereCurrentFileLocks( (F)->FileLock )) ? \
                                                                                    \
        FastIoIsQuestionable :                                                      \
                                                                                    \
        FastIoIsPossible))                                                          \
)


//
//  The FSP level dispatch/main routine.  This is the routine that takes
//  IRP's off of the work queue and calls the appropriate FSP level
//  work routine.
//

VOID
CdFspDispatch (                             //  implemented in FspDisp.c
    IN PIRP_CONTEXT IrpContext
    );

VOID
CdFspClose (                                //  implemented in Close.c
    IN PVCB Vcb OPTIONAL
    );

//
//  The following routines are the entry points for the different operations
//  based on the IrpSp major functions.
//

NTSTATUS
CdCommonCreate (                            //  Implemented in Create.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonClose (                             //  Implemented in Close.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonRead (                              //  Implemented in Read.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonQueryInfo (                         //  Implemented in FileInfo.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonSetInfo (                           //  Implemented in FileInfo.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonQueryVolInfo (                      //  Implemented in VolInfo.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonDirControl (                        //  Implemented in DirCtrl.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonFsControl (                         //  Implemented in FsCtrl.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonDevControl (                        //  Implemented in DevCtrl.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonLockControl (                       //  Implemented in LockCtrl.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonCleanup (                           //  Implemented in Cleanup.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );

NTSTATUS
CdCommonPnp (                               //  Implemented in Pnp.c
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    );


//
//  The following macros are used to establish the semantics needed
//  to do a return from within a try-finally clause.  As a rule every
//  try clause must end with a label call try_exit.  For example,
//
//      try {
//              :
//              :
//
//      try_exit: NOTHING;
//      } finally {
//
//              :
//              :
//      }
//
//  Every return statement executed inside of a try clause should use the
//  try_return macro.  If the compiler fully supports the try-finally construct
//  then the macro should be
//
//      #define try_return(S)  { return(S); }
//
//  If the compiler does not support the try-finally construct then the macro
//  should be
//
//      #define try_return(S)  { S; goto try_exit; }
//

#define try_return(S) { S; goto try_exit; }
#define try_leave(S) { S; leave; }

#endif // _CDPROCS_
