Sample Code

Windows Driver Samples/ CDFS File System Driver/ C++/ cdprocs.h/

/*++

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.


--*/

#ifndef _CDPROCS_
#define _CDPROCS_

#pragma warning( disable: 4127 ) // conditional expression is constant

#pragma warning( push )
#pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union
#pragma warning( disable: 4214 ) // nonstandard extension used : bit field types

#include <ntifs.h>

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

#ifndef INLINE
#define INLINE __inline
#endif

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

#pragma warning( pop )

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

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

#ifndef Min
#define Min(a, b)   ((a) < (b) ? (a) : (b))
#endif

#ifndef Max
#define Max(a, b)   ((a) > (b) ? (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.
//

_Requires_lock_held_(_Global_critical_region_)
VOID
CdLookupAllocation (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _In_ LONGLONG FileOffset,
    _Out_ PLONGLONG DiskOffset,
    _Out_ PULONG ByteCount
    );

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

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

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

_At_(Fcb->NodeByteSize, _In_range_(>=, FIELD_OFFSET( FCB, FcbType )))
VOID
CdInitializeMcb (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_updates_bytes_(Fcb->NodeByteSize) PFCB Fcb
    );

_At_(Fcb->NodeByteSize, _In_range_(>=, FIELD_OFFSET( FCB, FcbType )))
_When_(Fcb->NodeTypeCode == CDFS_NTC_FCB_PATH_TABLE, _At_(Fcb->NodeByteSize, _In_range_(==, SIZEOF_FCB_INDEX)))
_When_(Fcb->NodeTypeCode == CDFS_NTC_FCB_INDEX, _At_(Fcb->NodeByteSize, _In_range_(==, SIZEOF_FCB_INDEX)))
_When_(Fcb->NodeTypeCode == CDFS_NTC_FCB_DATA, _At_(Fcb->NodeByteSize, _In_range_(==, SIZEOF_FCB_DATA)))
VOID
CdUninitializeMcb (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_updates_bytes_(Fcb->NodeByteSize) PFCB Fcb
    );

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

VOID
CdCreateInternalStream (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PVCB Vcb,
    _Inout_ PFCB Fcb,
    _In_ PUNICODE_STRING Name
    );

VOID
CdDeleteInternalStream (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB Fcb
    );

NTSTATUS
CdCompleteMdl (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp
    );

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdPurgeVolume (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PVCB Vcb,
    _In_ BOOLEAN DismountUnderway
    );

VOID
INLINE
CdVerifyOrCreateDirStreamFile (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb
    )
{
    //
    //  Unsafe test to see if call / lock neccessary.
    //
    
    if (NULL == Fcb->FileObject) {
        
        CdCreateInternalStream( IrpContext,
                                Fcb->Vcb,
                                Fcb, 
                                &Fcb->FileNamePrefix.ExactCaseName.FileName);
    }
}


//
//  VOID
//  CdUnpinData (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ 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.
//

_Requires_lock_held_(_Global_critical_region_)
VOID
CdFreeDirCache (
    _In_ PIRP_CONTEXT IrpContext
    );

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdNonCachedRead (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _In_ LONGLONG StartingOffset,
    _In_ ULONG ByteCount
    );

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdNonCachedXARead (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _In_ LONGLONG StartingOffset,
    _In_ ULONG ByteCount
    );

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdVolumeDasdWrite (
    _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 ReturnError,
    _Out_writes_bytes_(ByteCount) PVOID Buffer,
    _In_ PDEVICE_OBJECT TargetDeviceObject
    );

NTSTATUS
CdCreateUserMdl (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ ULONG BufferLength,
    _In_ BOOLEAN RaiseOnError,
    _In_ LOCK_OPERATION Operation
    );

NTSTATUS
FASTCALL
CdPerformDevIoCtrl (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ ULONG IoControlCode,
    _In_ PDEVICE_OBJECT Device,
    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
    _In_ ULONG OutputBufferLength,
    _In_ BOOLEAN InternalDeviceIoControl,
    _In_ BOOLEAN OverrideVerify,
    _Out_opt_ PIO_STATUS_BLOCK Iosb
    );

NTSTATUS
CdPerformDevIoCtrlEx (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ ULONG IoControlCode,
    _In_ PDEVICE_OBJECT Device,
    _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
    _In_ ULONG InputBufferLength,
    _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
    _In_ ULONG OutputBufferLength,
    _In_ BOOLEAN InternalDeviceIoControl,
    _In_ BOOLEAN OverrideVerify,
    _Out_opt_ PIO_STATUS_BLOCK Iosb
    );

NTSTATUS
CdHijackIrpAndFlushDevice (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp,
    _In_ PDEVICE_OBJECT TargetDeviceObject
    );


//
//  VOID
//  CdMapUserBuffer (
//      _In_ PIRP_CONTEXT IrpContext
//      _Out_ PVOID UserBuffer
//      );
//
//  Returns pointer to sys address.  Will raise on failure.
//
//
//  VOID
//  CdLockUserBuffer (
//      _Inout_ 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,OP) {                        \
    if ((IC)->Irp->MdlAddress == NULL) {                    \
        (VOID) CdCreateUserMdl( (IC), (BL), TRUE, (OP) );   \
    }                                                       \
}


//
//  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,
    _Inout_ PDIRENT_ENUM_CONTEXT NextDirContext
    );

_At_(Dirent->CdTime, _Post_notnull_)
VOID
CdUpdateDirentFromRawDirent (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _In_ PDIRENT_ENUM_CONTEXT DirContext,
    _Inout_ PDIRENT Dirent
    );

VOID
CdUpdateDirentName (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PDIRENT Dirent,
    _In_ ULONG IgnoreCase
    );

_Success_(return != FALSE) BOOLEAN
CdFindFile (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _In_ PCD_NAME Name,
    _In_ BOOLEAN IgnoreCase,
    _Inout_ PFILE_ENUM_CONTEXT FileContext,
    _Out_ PCD_NAME *MatchingName
    );

BOOLEAN
CdFindDirectory (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _In_ PCD_NAME Name,
    _In_ BOOLEAN IgnoreCase,
    _Inout_ PFILE_ENUM_CONTEXT FileContext
    );

_At_(FileContext->ShortName.FileName.MaximumLength, _In_range_(>=, BYTE_COUNT_8_DOT_3))
BOOLEAN
CdFindFileByShortName (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _In_ PCD_NAME Name,
    _In_ BOOLEAN IgnoreCase,
    _In_ ULONG ShortNameDirentOffset,
    _Inout_ PFILE_ENUM_CONTEXT FileContext
    );

BOOLEAN
CdLookupNextInitialFileDirent (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb,
    _Inout_ 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,
//      _Out_ PFILE_ENUM_CONTEXT FileContext
//      );
//
//
//  VOID
//  CdInitializeDirent (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Out_ PDIRENT Dirent
//      );
//
//  VOID
//  CdInitializeDirContext (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Out_ PDIRENT_ENUM_CONTEXT DirContext
//      );
//
//  VOID
//  CdCleanupDirent (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PDIRENT Dirent
//      );
//
//  VOID
//  CdCleanupDirContext (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PDIRENT_ENUM_CONTEXT DirContext
//      );
//
//  VOID
//  CdLookupInitialFileDirent (
//      _In_ PIRP_CONTEXT IrpContext,
//      _In_ PFCB Fcb,
//      _Out_ 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 )) {       \
        CdFreePool( &(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;

_When_(TypeOfOpen == UnopenedFileObject, _At_(Fcb, _In_opt_))
_When_(TypeOfOpen != UnopenedFileObject, _At_(Fcb, _In_))
VOID
CdSetFileObject (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFILE_OBJECT FileObject,
    _In_ TYPE_OF_OPEN TypeOfOpen,
    PFCB Fcb,
    _In_opt_ PCCB Ccb
    );

_When_(return == UnopenedFileObject, _At_(*Fcb, _Post_null_))
_When_(return != UnopenedFileObject, _At_(Fcb, _Outptr_))
_When_(return == UnopenedFileObject, _At_(*Ccb, _Post_null_))
_When_(return != UnopenedFileObject, _At_(Ccb, _Outptr_))
TYPE_OF_OPEN
CdDecodeFileObject (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFILE_OBJECT FileObject,
    PFCB *Fcb,
    PCCB *Ccb
    );

TYPE_OF_OPEN
CdFastDecodeFileObject (
    _In_ PFILE_OBJECT FileObject,
    _Out_ PFCB *Fcb
    );

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

_Post_satisfies_(_Old_(CdName->FileName.Length) >=
                 CdName->FileName.Length + CdName->VersionString.Length)
VOID
CdConvertNameToCdName (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PCD_NAME CdName
    );

VOID
CdConvertBigToLittleEndian (
    _In_ PIRP_CONTEXT IrpContext,
    _In_reads_bytes_(ByteCount) PCHAR BigEndian,
    _In_ ULONG ByteCount,
    _Out_writes_bytes_(ByteCount) PCHAR LittleEndian
    );

VOID
CdUpcaseName (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PCD_NAME Name,
    _Inout_ PCD_NAME UpcaseName
    );

VOID
CdDissectName (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PUNICODE_STRING RemainingName,
    _Out_ PUNICODE_STRING FinalName
    );

BOOLEAN
CdIsLegalName (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PUNICODE_STRING FileName
    );

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

VOID
CdGenerate8dot3Name (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PUNICODE_STRING FileName,
    _In_ ULONG DirentOffset,
    _Out_writes_bytes_to_(BYTE_COUNT_8_DOT_3, *ShortByteCount) 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
//

_Requires_lock_held_(_Global_critical_region_)
_Requires_lock_held_(Vcb->VcbResource)
NTSTATUS
CdLockVolumeInternal (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PVCB Vcb,
    _In_opt_ PFILE_OBJECT FileObject
    );

NTSTATUS
CdUnlockVolumeInternal (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PVCB Vcb,
    _In_opt_ PFILE_OBJECT FileObject
    );

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

VOID
CdLookupPathEntry (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ ULONG PathEntryOffset,
    _In_ ULONG Ordinal,
    _In_ BOOLEAN VerifyBounds,
    _Inout_ PCOMPOUND_PATH_ENTRY CompoundPathEntry
    );

BOOLEAN
CdLookupNextPathEntry (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PPATH_ENUM_CONTEXT PathContext,
    _Inout_ PPATH_ENTRY PathEntry
    );

_Success_(return != FALSE)
BOOLEAN
CdFindPathEntry (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PFCB ParentFcb,
    _In_ PCD_NAME DirName,
    _In_ BOOLEAN IgnoreCase,
    _Inout_ PCOMPOUND_PATH_ENTRY CompoundPathEntry
    );

VOID
CdUpdatePathEntryName (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PPATH_ENTRY PathEntry,
    _In_ BOOLEAN IgnoreCase
    );

//
//  VOID
//  CdInitializeCompoundPathEntry (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Out_ PCOMPOUND_PATH_ENTRY CompoundPathEntry
//      );
//
//  VOID
//  CdCleanupCompoundPathEntry (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Out_ 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) {                                      \
        CdFreePool( &(CP)->PathContext.Data );                                   \
    }                                                                           \
    if (FlagOn( (CP)->PathEntry.Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER )) {        \
        CdFreePool( &(CP)->PathEntry.CdDirName.FileName.Buffer );                \
    }                                                                           \
}

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

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

VOID
CdRemovePrefix (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB Fcb
    );

_Requires_lock_held_(_Global_critical_region_)
VOID
CdFindPrefix (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB *CurrentFcb,
    _Inout_ 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;

_Requires_lock_held_(_Global_critical_region_)
_When_(Type == AcquireExclusive && return != FALSE, _Acquires_exclusive_lock_(*Resource))
_When_(Type == AcquireShared && return != FALSE, _Acquires_shared_lock_(*Resource))
_When_(Type == AcquireSharedStarveExclusive && return != FALSE, _Acquires_shared_lock_(*Resource))
_When_(IgnoreWait == FALSE, _Post_satisfies_(return == TRUE))
BOOLEAN
CdAcquireResource (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ 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,
//      _Inout_ PVCB Vcb,
//      _In_ BOOLEAN IgnoreWait
//      );
//
//  BOOLEAN
//  CdAcquireVcbShared (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PVCB Vcb,
//      _In_ BOOLEAN IgnoreWait
//      );
//
//  VOID
//  CdReleaseVcb (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PVCB Vcb
//      );
//
//  VOID
//  CdAcquireAllFiles (
//      _In_ PIRP_CONTEXT,
//      _In_ PVCB Vcb
//      );
//
//  VOID
//  CdReleaseAllFiles (
//      _In_ PIRP_CONTEXT,
//      _In_ PVCB Vcb
//      );
//
//  VOID
//  CdAcquireFileExclusive (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb,
//      );
//
//  VOID
//  CdAcquireFileShared (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//      );
//
//  VOID
//  CdReleaseFile (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//    );
//
//  BOOLEAN
//  CdAcquireFcbExclusive (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb,
//      _In_ BOOLEAN IgnoreWait
//      );
//
//  BOOLEAN
//  CdAcquireFcbShared (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb,
//      _In_ BOOLEAN IgnoreWait
//      );
//
//  BOOLEAN
//  CdReleaseFcb (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//      );
//
//  VOID
//  CdLockCdData (
//      );
//
//  VOID
//  CdUnlockCdData (
//      );
//
//  VOID
//  CdLockVcb (
//      _In_ PIRP_CONTEXT IrpContext
//      );
//
//  VOID
//  CdUnlockVcb (
//      _In_ PIRP_CONTEXT IrpContext
//      );
//
//  VOID
//  CdLockFcb (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//      );
//
//  VOID
//  CdUnlockFcb (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//      );
//


#define CdAcquireCacheForRead( IC)                                                      \
    ExAcquireResourceSharedLite( &(IC)->Vcb->SectorCacheResource, TRUE)
    
#define CdAcquireCacheForUpdate( IC)                                                    \
    ExAcquireResourceExclusiveLite( &(IC)->Vcb->SectorCacheResource, TRUE)
    
#define CdReleaseCache( IC)                                                             \
    ExReleaseResourceLite( &(IC)->Vcb->SectorCacheResource);

#define CdConvertCacheToShared( IC)                                                     \
    ExConvertExclusiveToSharedLite( &(IC)->Vcb->SectorCacheResource);

#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 );                                               \
    NT_ASSERT( NULL == (V)->VcbLockThread);                                             \
    (V)->VcbLockThread = PsGetCurrentThread()

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

#if defined(_PREFAST_)

_Success_(return)
_IRQL_saves_global_(OldIrql, FastMutex)
BOOLEAN DummySaveIrql(_Inout_ PFAST_MUTEX FastMutex);

_Success_(return)
_IRQL_restores_global_(OldIrql, FastMutex)
BOOLEAN DummyRestoreIrql(_Inout_ PFAST_MUTEX FastMutex);
#endif // _PREFAST_

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

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

//
//  The following macro is used to retrieve the oplock structure within
//  the Fcb. This structure was moved to the advanced Fcb header
//  in Win8.
//

#if (NTDDI_VERSION >= NTDDI_WIN8)

#define CdGetFcbOplock(F)   &(F)->Header.Oplock

#else

#define CdGetFcbOplock(F)   &(F)->Oplock

#endif

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

VOID
CdNoopRelease (
    _In_ PVOID Fcb
    );

_Requires_lock_held_(_Global_critical_region_)
_When_(return!=0, _Acquires_shared_lock_(*Fcb->Resource))
BOOLEAN
CdAcquireForCache (
    _Inout_ PFCB Fcb,
    _In_ BOOLEAN Wait
    );

_Requires_lock_held_(_Global_critical_region_)
_Releases_lock_(*Fcb->Resource)
VOID
CdReleaseFromCache (
    _Inout_ PFCB Fcb
    );

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdFilterCallbackAcquireForCreateSection (
    _In_ PFS_FILTER_CALLBACK_DATA CallbackData,
    _Unreferenced_parameter_ PVOID *CompletionContext
    );

_Function_class_(FAST_IO_RELEASE_FILE)
_Requires_lock_held_(_Global_critical_region_)
VOID
CdReleaseForCreateSection (
    _In_ PFILE_OBJECT FileObject
    );

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

VOID
CdInitializeVcb (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PVCB Vcb,
    _In_ __drv_aliasesMem PDEVICE_OBJECT TargetDeviceObject,
    _In_ __drv_aliasesMem PVPB Vpb,
    _In_ __drv_aliasesMem PCDROM_TOC_LARGE CdromToc,
    _In_ ULONG TocLength,
    _In_ ULONG TocTrackCount,
    _In_ ULONG TocDiskFlags,
    _In_ ULONG BlockFactor,
    _In_ ULONG MediaChangeCount
    );

VOID
CdUpdateVcbFromVolDescriptor (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PVCB Vcb,
    _In_reads_bytes_opt_(SECTOR_SIZE) PCHAR RawIsoVd
    );

VOID
CdDeleteVcb (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PVCB Vcb
    );

PFCB
CdCreateFcb (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ FILE_ID FileId,
    _In_ NODE_TYPE_CODE NodeTypeCode,
    _Out_opt_ PBOOLEAN FcbExisted
    );

VOID
CdInitializeFcbFromPathEntry (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB Fcb,
    _In_opt_ PFCB ParentFcb,
    _In_ PPATH_ENTRY PathEntry
    );

VOID
CdInitializeFcbFromFileContext (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB Fcb,
    _In_ PFCB ParentFcb,
    _In_ PFILE_ENUM_CONTEXT FileContext
    );

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

VOID
CdDeleteCcb (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ __drv_freesMem( Pool ) PCCB Ccb
    );

_When_(RaiseOnError || return, _At_(Fcb->FileLock, _Post_notnull_))
_When_(RaiseOnError, _At_(IrpContext, _Pre_notnull_))
BOOLEAN
CdCreateFileLock (
    _In_opt_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB Fcb,
    _In_ BOOLEAN RaiseOnError
    );

VOID
CdDeleteFileLock (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFILE_LOCK FileLock
    );

_Ret_valid_ 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 (
//      _Inout_ PIRP_CONTEXT_LITE IrpContextLite
//      );
//

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

#define CdFreeIrpContextLite(ICL)  \
    CdFreePool( &(ICL) )

_Requires_lock_held_(_Global_critical_region_)
VOID
CdTeardownStructures (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB StartingFcb,
    _Out_ PBOOLEAN RemovedStartingFcb
    );

//
//  VOID
//  CdIncrementCleanupCounts (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//      );
//
//  VOID
//  CdDecrementCleanupCounts (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//      );
//
//  VOID
//  CdIncrementReferenceCounts (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb,
//      _In_ ULONG ReferenceCount
//      _In_ ULONG UserReferenceCount
//      );
//
//  VOID
//  CdDecrementReferenceCounts (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb,
//      _In_ ULONG ReferenceCount
//      _In_ ULONG UserReferenceCount
//      );
//
//  VOID
//  CdIncrementFcbReference (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ PFCB Fcb
//      );
//
//  VOID
//  CdDecrementFcbReference (
//      _In_ PIRP_CONTEXT IrpContext,
//      _Inout_ 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)     CdFreePool( &(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_LARGE CdromToc,
    _Inout_ PULONG Length,
    _Out_ PULONG TrackCount,
    _Inout_ 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              NonPagedPoolNx
#define CdNonPagedPoolCacheAligned  NonPagedPoolNxCacheAligned


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


INLINE
BOOLEAN
CdOperationIsDasdOpen (
    _In_ PIRP_CONTEXT IrpContext
    )
{
    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->Irp);
    
    return ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
            (IrpSp->FileObject->FileName.Length == 0) &&
            (IrpSp->FileObject->RelatedFileObject == NULL));
}

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdPerformVerify (
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp,
    _In_ PDEVICE_OBJECT DeviceToVerify
    );

_Requires_lock_held_(_Global_critical_region_)
BOOLEAN
CdCheckForDismount (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PVCB Vcb,
    _In_ BOOLEAN Force
    );

BOOLEAN
CdMarkDevForVerifyIfVcbMounted (
    _Inout_ PVCB Vcb
    );

VOID
CdVerifyVcb (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PVCB Vcb
    );

BOOLEAN
CdVerifyFcbOperation (
    _In_opt_ PIRP_CONTEXT IrpContext,
    _In_ PFCB Fcb
    );

_Requires_lock_held_(_Global_critical_region_)
BOOLEAN
CdDismountVcb (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ 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
//

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdFsdPostRequest (
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp
    );

_Requires_lock_held_(_Global_critical_region_)
VOID
CdPrePostIrp (
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp
    );

_Requires_lock_held_(_Global_critical_region_)
VOID
CdOplockComplete (
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ 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                                       \
)

INLINE
ULONG
SectorsFromLlBytes( 
    ULONGLONG Bytes
) {

    return (ULONG)(Bytes >> 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));\
    }

//
//  This macro copies an unaligned src longword to a dst longword,
//  performing an little/big endian swap.
//

#define SwapCopyUchar4(Dst,Src) {                                        \
    *((UNALIGNED UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src) + 3);     \
    *((UNALIGNED UCHAR1 *)(Dst) + 1) = *((UNALIGNED UCHAR1 *)(Src) + 2); \
    *((UNALIGNED UCHAR1 *)(Dst) + 2) = *((UNALIGNED UCHAR1 *)(Src) + 1); \
    *((UNALIGNED UCHAR1 *)(Dst) + 3) = *((UNALIGNED UCHAR1 *)(Src));     \
}

VOID
CdLbnToMmSsFf (
    _In_ ULONG Blocks,
    _Out_writes_(3) PUCHAR Msf
    );

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

//  NTSTATUS
//  CdFsdDispatch (
//      _In_ PDEVICE_OBJECT DeviceObject,
//      _Inout_ PIRP Irp
//      );

DRIVER_DISPATCH CdFsdDispatch;

LONG
CdExceptionFilter (
    _Inout_ PIRP_CONTEXT IrpContext,
    _In_ PEXCEPTION_POINTERS ExceptionPointer
    );

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdProcessException (
    _In_opt_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp,
    _In_ NTSTATUS ExceptionCode
    );

VOID
CdCompleteRequest (
    _Inout_opt_ PIRP_CONTEXT IrpContext,
    _Inout_opt_ PIRP Irp,
    _In_ NTSTATUS Status
    );

//
//  VOID
//  CdRaiseStatus (
//      _In_ PRIP_CONTEXT IrpContext,
//      _In_ NT_STATUS Status
//      );
//
//  VOID
//  CdNormalizeAndRaiseStatus (
//      _In_ PRIP_CONTEXT IrpContext,
//      _In_ NT_STATUS Status
//      );
//

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

#define AssertVerifyDeviceIrp(I)                                                    \
    NT_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


#ifdef CD_SANITY

DECLSPEC_NORETURN
VOID
CdRaiseStatusEx (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ NTSTATUS Status,
    _In_ BOOLEAN NormalizeStatus,
    _In_opt_ ULONG FileId,
    _In_opt_ ULONG Line
    );

#else

INLINE
DECLSPEC_NORETURN
VOID
CdRaiseStatusEx(
    _In_ PIRP_CONTEXT IrpContext,
    _In_ NTSTATUS Status,
    _In_ BOOLEAN NormalizeStatus,
    _In_ ULONG Fileid,
    _In_ ULONG Line
    )
{
    if (NormalizeStatus)  {

        IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR);
    }
    else {

        IrpContext->ExceptionStatus = Status;
    }

    IrpContext->RaisedAtLineFile = (Fileid << 16) | Line;

    ExRaiseStatus( IrpContext->ExceptionStatus );
}

#endif

#define CdRaiseStatus( IC, S)               CdRaiseStatusEx( (IC), (S), FALSE, BugCheckFileId, __LINE__);
#define CdNormalizeAndRaiseStatus( IC, S)   CdRaiseStatusEx( (IC), (S), TRUE, BugCheckFileId, __LINE__);

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

//  _Success_(return != FALSE)
//  BOOLEAN
//  CdFastQueryBasicInfo (
//      _In_ PFILE_OBJECT FileObject,
//      _In_ BOOLEAN Wait,
//      _Out_ PFILE_BASIC_INFORMATION Buffer,
//      _Out_ PIO_STATUS_BLOCK IoStatus,
//      _In_ PDEVICE_OBJECT DeviceObject
//      );

FAST_IO_QUERY_BASIC_INFO CdFastQueryBasicInfo;

//  _Success_(return != FALSE)
//  BOOLEAN
//  CdFastQueryStdInfo (
//      _In_ PFILE_OBJECT FileObject,
//      _In_ BOOLEAN Wait,
//      _Out_ PFILE_STANDARD_INFORMATION Buffer,
//      _Out_ PIO_STATUS_BLOCK IoStatus,
//      _In_ PDEVICE_OBJECT DeviceObject
//      );

FAST_IO_QUERY_STANDARD_INFO CdFastQueryStdInfo;

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

FAST_IO_LOCK CdFastLock;

//  BOOLEAN
//  CdFastUnlockSingle (
//      _In_ PFILE_OBJECT FileObject,
//      _In_ PLARGE_INTEGER FileOffset,
//      _In_ PLARGE_INTEGER Length,
//      _In_ PEPROCESS ProcessId,
//      _In_ ULONG Key,
//      _Out_ PIO_STATUS_BLOCK IoStatus,
//      _In_ PDEVICE_OBJECT DeviceObject
//      );

FAST_IO_UNLOCK_SINGLE CdFastUnlockSingle;

//  BOOLEAN
//  CdFastUnlockAll (
//      _In_ PFILE_OBJECT FileObject,
//      _In_ PEPROCESS ProcessId,
//      _Out_ PIO_STATUS_BLOCK IoStatus,
//      _In_ PDEVICE_OBJECT DeviceObject
//      );

FAST_IO_UNLOCK_ALL CdFastUnlockAll;

//  BOOLEAN
//  CdFastUnlockAllByKey (
//      _In_ PFILE_OBJECT FileObject,
//      _In_ PVOID ProcessId,
//      _In_ ULONG Key,
//      _Out_ PIO_STATUS_BLOCK IoStatus,
//      _In_ PDEVICE_OBJECT DeviceObject
//      );

FAST_IO_UNLOCK_ALL_BY_KEY CdFastUnlockAllByKey;

//  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
//      );

FAST_IO_CHECK_IF_POSSIBLE CdFastIoCheckIfPossible;

//  _Success_(return != FALSE)
//  BOOLEAN
//  CdFastQueryNetworkInfo (
//      _In_ PFILE_OBJECT FileObject,
//      _In_ BOOLEAN Wait,
//      _Out_ PFILE_NETWORK_OPEN_INFORMATION Buffer,
//      _Out_ PIO_STATUS_BLOCK IoStatus,
//      _In_ PDEVICE_OBJECT DeviceObject
//      );

FAST_IO_QUERY_NETWORK_OPEN_INFO CdFastQueryNetworkInfo;

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

VOID
CdSetThreadContext (
    _Inout_ PIRP_CONTEXT IrpContext,
    _In_ PTHREAD_CONTEXT ThreadContext
    );


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

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

ULONG
CdSerial32 (
    _In_reads_bytes_(ByteCount) 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( CdGetFcbOplock(F) )) ?                          \
                                                                                    \
     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
//      _Inout_ PIRP_CONTEXT IrpContext
//      );

WORKER_THREAD_ROUTINE CdFspDispatch;

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

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

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

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

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

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdCommonWrite (                             //  Implemented in Write.c
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp
    );

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

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

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

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

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

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

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

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

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

_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdCommonShutdown (                         //  Implemented in Shutdown.c
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ 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; }

//
//  Encapsulate safe pool freeing
//

INLINE
VOID
CdFreePool(
    _Inout_ _At_(*Pool, __drv_freesMem(Mem) _Post_null_) PVOID *Pool
    )
{
    if (*Pool != NULL) {

        ExFreePool(*Pool);
        *Pool = NULL;
    }
}

#endif // _CDPROCS_


Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS