|
|
/*++
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_
|