/*++ Copyright (c) 1989-2000 Microsoft Corporation Module Name: FatProcs.h Abstract: This module defines all of the globally used procedures in the FAT file system. --*/ #ifndef _FATPROCS_ #define _FATPROCS_ #ifdef _MSC_VER #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 #endif #include #include #include #include #include #include #include #ifdef __REACTOS__ #include #endif #ifdef __REACTOS__ // Downgrade unsupported NT6.2+ features. #undef MdlMappingNoExecute #define MdlMappingNoExecute 0 #define NonPagedPoolNx NonPagedPool #define NonPagedPoolNxCacheAligned NonPagedPoolCacheAligned #undef POOL_NX_ALLOCATION #define POOL_NX_ALLOCATION 0 // Moved up: needed in 'fatstruc.h'. typedef enum _TYPE_OF_OPEN { UnopenedFileObject = 1, UserFileOpen, UserDirectoryOpen, UserVolumeOpen, VirtualVolumeFile, DirectoryFile, EaFile, } TYPE_OF_OPEN; #endif #include "nodetype.h" #include "fat.h" #include "lfn.h" #include "fatstruc.h" #include "fatdata.h" #ifdef _MSC_VER #pragma warning( pop ) #endif #ifndef INLINE #define INLINE __inline #endif #define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I))) #ifndef MAX_ULONG #define MAX_ULONG ((ULONG)-1) #endif #ifndef MAX_USHORT #define MAX_USHORT ((USHORT)-1) #endif // // We must explicitly tag our allocations. // #undef FsRtlAllocatePool #undef FsRtlAllocatePoolWithQuota // // A function that returns finished denotes if it was able to complete the // operation (TRUE) or could not complete the operation (FALSE) because the // wait value stored in the irp context was false and we would have had // to block for a resource or I/O // typedef BOOLEAN FINISHED; // // Size (characters) of stack allocated name component buffers in // the create/rename paths. // #define FAT_CREATE_INITIAL_NAME_BUF_SIZE 32 // // Some string buffer handling functions, implemented in strucsup.c // VOID FatFreeStringBuffer ( _Inout_ PVOID String ); VOID FatExtendString( _Inout_ PVOID String, _In_ USHORT DesiredBufferSize, _In_ BOOLEAN FreeOldBuffer, __out_opt PBOOLEAN NeedsFree ); VOID FatEnsureStringBufferEnough ( _Inout_ PVOID String, _In_ USHORT DesiredBufferSize ); BOOLEAN FatAddMcbEntry ( IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, IN LBO Lbo, IN ULONG SectorCount ); BOOLEAN FatLookupMcbEntry ( IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, OUT PLBO Lbo, OUT PULONG ByteCount OPTIONAL, OUT PULONG Index OPTIONAL ); BOOLEAN FatLookupLastMcbEntry ( IN PVCB Vcb, IN PLARGE_MCB Mcb, OUT PVBO Vbo, OUT PLBO Lbo, OUT PULONG Index OPTIONAL ); BOOLEAN FatGetNextMcbEntry ( IN PVCB Vcb, IN PLARGE_MCB Mcb, IN ULONG RunIndex, OUT PVBO Vbo, OUT PLBO Lbo, OUT PULONG ByteCount ); VOID FatRemoveMcbEntry ( IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, IN ULONG SectorCount ); // // File access check routine, implemented in AcChkSup.c // BOOLEAN FatCheckFileAccess ( PIRP_CONTEXT IrpContext, IN UCHAR DirentAttributes, IN PACCESS_MASK DesiredAccess ); BOOLEAN FatCheckManageVolumeAccess ( _In_ PIRP_CONTEXT IrpContext, _In_ PACCESS_STATE AccessState, _In_ KPROCESSOR_MODE ProcessorMode ); NTSTATUS FatExplicitDeviceAccessGranted ( IN PIRP_CONTEXT IrpContext, IN PDEVICE_OBJECT DeviceObject, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE ProcessorMode ); // // Allocation support routines, implemented in AllocSup.c // static INLINE BOOLEAN FatIsIoRangeValid ( IN PVCB Vcb, IN LARGE_INTEGER Start, IN ULONG Length ) /*++ Routine Description: This routine enforces the restriction that object space must be representable in 32 bits. Arguments: Vcb - the volume the range is on Start - starting byte (zero based) of the range Length - size of the range HeaderSize - if the file has a header Return Value: BOOLEAN - if, considering the cluster size, the neccesary size of the object to contain the range can be represented in 32 bits. --*/ { UNREFERENCED_PARAMETER( Vcb ); // // The only restriction on a FAT object is that the filesize must // fit in 32bits, i.e. <= 0xffffffff. This then implies that the // range of valid byte offsets is [0, fffffffe]. // // Two phases which check for illegality // // - if the high 32bits are nonzero // - if the length would cause a 32bit overflow // return !(Start.HighPart || Start.LowPart + Length < Start.LowPart); } // // This strucure is used by FatLookupFatEntry to remember a pinned page // of fat. // typedef struct _FAT_ENUMERATION_CONTEXT { VBO VboOfPinnedPage; PBCB Bcb; PVOID PinnedPage; } FAT_ENUMERATION_CONTEXT, *PFAT_ENUMERATION_CONTEXT; VOID FatLookupFatEntry ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG FatIndex, IN OUT PULONG FatEntry, IN OUT PFAT_ENUMERATION_CONTEXT Context ); VOID FatSetupAllocationSupport ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); VOID FatTearDownAllocationSupport ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatLookupFileAllocation ( IN PIRP_CONTEXT IrpContext, IN PFCB FcbOrDcb, IN VBO Vbo, OUT PLBO Lbo, OUT PULONG ByteCount, OUT PBOOLEAN Allocated, OUT PBOOLEAN EndOnMax, OUT PULONG Index OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) VOID FatAddFileAllocation ( IN PIRP_CONTEXT IrpContext, IN PFCB FcbOrDcb, IN PFILE_OBJECT FileObject OPTIONAL, IN ULONG AllocationSize ); _Requires_lock_held_(_Global_critical_region_) VOID FatTruncateFileAllocation ( IN PIRP_CONTEXT IrpContext, IN PFCB FcbOrDcb, IN ULONG AllocationSize ); _Requires_lock_held_(_Global_critical_region_) VOID FatLookupFileAllocationSize ( IN PIRP_CONTEXT IrpContext, IN PFCB FcbOrDcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatAllocateDiskSpace ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG AbsoluteClusterHint, IN OUT PULONG ByteCount, IN BOOLEAN ExactMatchRequired, OUT PLARGE_MCB Mcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatDeallocateDiskSpace ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PLARGE_MCB Mcb, IN BOOLEAN ZeroOnDeallocate ); _Requires_lock_held_(_Global_critical_region_) VOID FatSplitAllocation ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN OUT PLARGE_MCB Mcb, IN VBO SplitAtVbo, OUT PLARGE_MCB RemainingMcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatMergeAllocation ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN OUT PLARGE_MCB Mcb, IN PLARGE_MCB SecondMcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatSetFatEntry ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG FatIndex, IN FAT_ENTRY FatEntry ); UCHAR FatLogOf( IN ULONG Value ); // // Buffer control routines for data caching, implemented in CacheSup.c // VOID FatReadVolumeFile ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb, OUT PVOID *Buffer ); _Requires_lock_held_(_Global_critical_region_) VOID FatPrepareWriteVolumeFile ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb, OUT PVOID *Buffer, IN BOOLEAN Reversible, IN BOOLEAN Zero ); _Requires_lock_held_(_Global_critical_region_) VOID FatReadDirectoryFile ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN VBO StartingVbo, IN ULONG ByteCount, IN BOOLEAN Pin, OUT PBCB *Bcb, OUT PVOID *Buffer, OUT PNTSTATUS Status ); _Requires_lock_held_(_Global_critical_region_) VOID FatPrepareWriteDirectoryFile ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb, OUT PVOID *Buffer, IN BOOLEAN Zero, IN BOOLEAN Reversible, OUT PNTSTATUS Status ); _Requires_lock_held_(_Global_critical_region_) VOID FatOpenDirectoryFile ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb ); PFILE_OBJECT FatOpenEaFile ( IN PIRP_CONTEXT IrpContext, IN PFCB EaFcb ); VOID FatCloseEaFile ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN FlushFirst ); _Requires_lock_held_(_Global_critical_region_) VOID FatSetDirtyBcb ( IN PIRP_CONTEXT IrpContext, IN PBCB Bcb, IN PVCB Vcb OPTIONAL, IN BOOLEAN Reversible ); VOID FatRepinBcb ( IN PIRP_CONTEXT IrpContext, IN PBCB Bcb ); VOID FatUnpinRepinnedBcbs ( IN PIRP_CONTEXT IrpContext ); FINISHED FatZeroData ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject, IN ULONG StartingZero, IN ULONG ByteCount ); NTSTATUS FatCompleteMdl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); VOID FatPinMappedData ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb ); NTSTATUS FatPrefetchPages ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN ULONG StartingPage, IN ULONG PageCount ); // // VOID // FatUnpinBcb ( // IN PIRP_CONTEXT IrpContext, // IN OUT PBCB Bcb, // ); // // // This macro unpins a Bcb, in the checked build make sure all // requests unpin all Bcbs before leaving. // #if DBG #define FatUnpinBcb(IRPCONTEXT,BCB) { \ if ((BCB) != NULL) { \ CcUnpinData((BCB)); \ NT_ASSERT( (IRPCONTEXT)->PinCount );\ (IRPCONTEXT)->PinCount -= 1; \ (BCB) = NULL; \ } \ } #else #define FatUnpinBcb(IRPCONTEXT,BCB) { \ if ((BCB) != NULL) { \ CcUnpinData((BCB)); \ (BCB) = NULL; \ } \ } #endif // DBG VOID FatInitializeCacheMap ( _In_ PFILE_OBJECT FileObject, _In_ PCC_FILE_SIZES FileSizes, _In_ BOOLEAN PinAccess, _In_ PCACHE_MANAGER_CALLBACKS Callbacks, _In_ PVOID LazyWriteContext ); VOID FatSyncUninitializeCacheMap ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject ); // // 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. // VOID FatPagingFileIo ( IN PIRP Irp, IN PFCB Fcb ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatNonCachedIo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PFCB FcbOrDcb, IN ULONG StartingVbo, IN ULONG ByteCount, IN ULONG UserByteCount, IN ULONG StreamFlags ); _Requires_lock_held_(_Global_critical_region_) VOID FatNonCachedNonAlignedRead ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PFCB FcbOrDcb, IN ULONG StartingVbo, IN ULONG ByteCount ); VOID FatMultipleAsync ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PIRP Irp, IN ULONG MultipleIrpCount, IN PIO_RUN IoRuns ); VOID FatSingleAsync ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN LBO Lbo, IN ULONG ByteCount, IN PIRP Irp ); VOID FatWaitSync ( IN PIRP_CONTEXT IrpContext ); VOID FatLockUserBuffer ( IN PIRP_CONTEXT IrpContext, IN OUT PIRP Irp, IN LOCK_OPERATION Operation, IN ULONG BufferLength ); PVOID FatBufferUserBuffer ( IN PIRP_CONTEXT IrpContext, IN OUT PIRP Irp, IN ULONG BufferLength ); PVOID FatMapUserBuffer ( IN PIRP_CONTEXT IrpContext, IN OUT PIRP Irp ); NTSTATUS FatToggleMediaEjectDisable ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN PreventRemoval ); NTSTATUS FatPerformDevIoCtrl ( IN PIRP_CONTEXT IrpContext, IN ULONG IoControlCode, IN PDEVICE_OBJECT Device, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN BOOLEAN OverrideVerify, OUT PIO_STATUS_BLOCK Iosb OPTIONAL ); PMDL FatBuildZeroMdl ( __in PIRP_CONTEXT IrpContext, __in ULONG Length ); // // Dirent support routines, implemented in DirSup.c // // // Tunneling is a deletion precursor (all tunneling cases do // not involve deleting dirents, however) // VOID FatTunnelFcbOrDcb ( IN PFCB FcbOrDcb, IN PCCB Ccb OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) ULONG FatCreateNewDirent ( IN PIRP_CONTEXT IrpContext, IN PDCB ParentDirectory, IN ULONG DirentsNeeded, IN BOOLEAN RescanDir ); _Requires_lock_held_(_Global_critical_region_) VOID FatInitializeDirectoryDirent ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN PDIRENT ParentDirent ); _Requires_lock_held_(_Global_critical_region_) VOID FatDeleteDirent ( IN PIRP_CONTEXT IrpContext, IN PFCB FcbOrDcb, IN PDELETE_CONTEXT DeleteContext OPTIONAL, IN BOOLEAN DeleteEa ); _Requires_lock_held_(_Global_critical_region_) VOID FatLocateDirent ( IN PIRP_CONTEXT IrpContext, IN PDCB ParentDirectory, IN PCCB Ccb, IN VBO OffsetToStartSearchFrom, IN OUT PULONG Flags, OUT PDIRENT *Dirent, OUT PBCB *Bcb, OUT PVBO ByteOffset, OUT PBOOLEAN FileNameDos OPTIONAL, IN OUT PUNICODE_STRING Lfn OPTIONAL, IN OUT PUNICODE_STRING OrigLfn OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) VOID FatLocateSimpleOemDirent ( IN PIRP_CONTEXT IrpContext, IN PDCB ParentDirectory, IN POEM_STRING FileName, OUT PDIRENT *Dirent, OUT PBCB *Bcb, OUT PVBO ByteOffset ); _Requires_lock_held_(_Global_critical_region_) BOOLEAN FatLfnDirentExists ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN PUNICODE_STRING Lfn, IN PUNICODE_STRING LfnTmp ); _Requires_lock_held_(_Global_critical_region_) VOID FatLocateVolumeLabel ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, OUT PDIRENT *Dirent, OUT PBCB *Bcb, OUT PVBO ByteOffset ); _Requires_lock_held_(_Global_critical_region_) VOID FatGetDirentFromFcbOrDcb ( IN PIRP_CONTEXT IrpContext, IN PFCB FcbOrDcb, IN BOOLEAN ReturnOnFailure, OUT PDIRENT *Dirent, OUT PBCB *Bcb ); _Requires_lock_held_(_Global_critical_region_) BOOLEAN FatIsDirectoryEmpty ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatDeleteFile ( IN PIRP_CONTEXT IrpContext, IN PDCB TargetDcb, IN ULONG LfnOffset, IN ULONG DirentOffset, IN PDIRENT Dirent, IN PUNICODE_STRING Lfn ); VOID FatConstructDirent ( IN PIRP_CONTEXT IrpContext, IN OUT PDIRENT Dirent, IN POEM_STRING FileName, IN BOOLEAN ComponentReallyLowercase, IN BOOLEAN ExtensionReallyLowercase, IN PUNICODE_STRING Lfn OPTIONAL, IN USHORT Attributes, IN BOOLEAN ZeroAndSetTimeFields, IN PLARGE_INTEGER SetCreationTime OPTIONAL ); VOID FatConstructLabelDirent ( IN PIRP_CONTEXT IrpContext, IN OUT PDIRENT Dirent, IN POEM_STRING Label ); _Requires_lock_held_(_Global_critical_region_) VOID FatSetFileSizeInDirent ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PULONG AlternativeFileSize OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) VOID FatSetFileSizeInDirentNoRaise ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PULONG AlternativeFileSize OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) VOID FatUpdateDirentFromFcb ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN PFCB FcbOrDcb, IN PCCB Ccb ); // // Generate a relatively unique static 64bit ID from a FAT Fcb/Dcb // // ULONGLONG // FatDirectoryKey (FcbOrDcb); // #define FatDirectoryKey(FcbOrDcb) ((ULONGLONG)((FcbOrDcb)->CreationTime.QuadPart ^ (FcbOrDcb)->FirstClusterOfFile)) // // The following routines are used to access and manipulate the // clusters containing EA data in the ea data file. They are // implemented in EaSup.c // // // VOID // FatUpcaseEaName ( // IN PIRP_CONTEXT IrpContext, // IN POEM_STRING EaName, // OUT POEM_STRING UpcasedEaName // ); // #define FatUpcaseEaName( IRPCONTEXT, NAME, UPCASEDNAME ) \ RtlUpperString( UPCASEDNAME, NAME ) _Requires_lock_held_(_Global_critical_region_) VOID FatGetEaLength ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PDIRENT Dirent, OUT PULONG EaLength ); _Requires_lock_held_(_Global_critical_region_) VOID FatGetNeedEaCount ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PDIRENT Dirent, OUT PULONG NeedEaCount ); _Requires_lock_held_(_Global_critical_region_) VOID FatCreateEa ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PUCHAR Buffer, IN ULONG Length, IN POEM_STRING FileName, OUT PUSHORT EaHandle ); _Requires_lock_held_(_Global_critical_region_) VOID FatDeleteEa ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN USHORT EaHandle, IN POEM_STRING FileName ); _Requires_lock_held_(_Global_critical_region_) VOID FatGetEaFile ( IN PIRP_CONTEXT IrpContext, IN OUT PVCB Vcb, OUT PDIRENT *EaDirent, OUT PBCB *EaBcb, IN BOOLEAN CreateFile, IN BOOLEAN ExclusiveFcb ); VOID FatReadEaSet ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN USHORT EaHandle, IN POEM_STRING FileName, IN BOOLEAN ReturnEntireSet, OUT PEA_RANGE EaSetRange ); _Requires_lock_held_(_Global_critical_region_) VOID FatDeleteEaSet ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PBCB EaBcb, OUT PDIRENT EaDirent, IN USHORT EaHandle, IN POEM_STRING Filename ); _Requires_lock_held_(_Global_critical_region_) VOID FatAddEaSet ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG EaSetLength, IN PBCB EaBcb, OUT PDIRENT EaDirent, OUT PUSHORT EaHandle, OUT PEA_RANGE EaSetRange ); VOID FatDeletePackedEa ( IN PIRP_CONTEXT IrpContext, IN OUT PEA_SET_HEADER EaSetHeader, IN OUT PULONG PackedEasLength, IN ULONG Offset ); VOID FatAppendPackedEa ( IN PIRP_CONTEXT IrpContext, IN OUT PEA_SET_HEADER *EaSetHeader, IN OUT PULONG PackedEasLength, IN OUT PULONG AllocationLength, IN PFILE_FULL_EA_INFORMATION FullEa, IN ULONG BytesPerCluster ); ULONG FatLocateNextEa ( IN PIRP_CONTEXT IrpContext, IN PPACKED_EA FirstPackedEa, IN ULONG PackedEasLength, IN ULONG PreviousOffset ); BOOLEAN FatLocateEaByName ( IN PIRP_CONTEXT IrpContext, IN PPACKED_EA FirstPackedEa, IN ULONG PackedEasLength, IN POEM_STRING EaName, OUT PULONG Offset ); BOOLEAN FatIsEaNameValid ( IN PIRP_CONTEXT IrpContext, IN OEM_STRING Name ); VOID FatPinEaRange ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT VirtualEaFile, IN PFCB EaFcb, IN OUT PEA_RANGE EaRange, IN ULONG StartingVbo, IN ULONG Length, IN NTSTATUS ErrorStatus ); VOID FatMarkEaRangeDirty ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT EaFileObject, IN OUT PEA_RANGE EaRange ); VOID FatUnpinEaRange ( IN PIRP_CONTEXT IrpContext, IN OUT PEA_RANGE EaRange ); // // The following macro computes the size of a full ea (not including // padding to bring it to a longword. A full ea has a 4 byte offset, // folowed by 1 byte flag, 1 byte name length, 2 bytes value length, // the name, 1 null byte, and the value. // // ULONG // SizeOfFullEa ( // IN PFILE_FULL_EA_INFORMATION FullEa // ); // #define SizeOfFullEa(EA) (4+1+1+2+(EA)->EaNameLength+1+(EA)->EaValueLength) // // The following routines are used to manipulate the fscontext fields // of the file object, implemented in FilObSup.c // #ifndef __REACTOS__ typedef enum _TYPE_OF_OPEN { UnopenedFileObject = 1, UserFileOpen, UserDirectoryOpen, UserVolumeOpen, VirtualVolumeFile, DirectoryFile, EaFile, } TYPE_OF_OPEN; #endif typedef enum _FAT_FLUSH_TYPE { NoFlush = 0, Flush, FlushAndInvalidate, FlushWithoutPurge } FAT_FLUSH_TYPE; VOID FatSetFileObject ( IN PFILE_OBJECT FileObject OPTIONAL, IN TYPE_OF_OPEN TypeOfOpen, IN PVOID VcbOrFcbOrDcb, IN PCCB Ccb OPTIONAL ); TYPE_OF_OPEN FatDecodeFileObject ( _In_ PFILE_OBJECT FileObject, _Outptr_ PVCB *Vcb, _Outptr_ PFCB *FcbOrDcb, _Outptr_ PCCB *Ccb ); _Requires_lock_held_(_Global_critical_region_) VOID FatPurgeReferencedFileObjects ( IN PIRP_CONTEXT IrpContext, IN PFCB FcbOrDcb, IN FAT_FLUSH_TYPE FlushType ); _Requires_lock_held_(_Global_critical_region_) VOID FatForceCacheMiss ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN FAT_FLUSH_TYPE FlushType ); // // File system control routines, implemented in FsCtrl.c // _Requires_lock_held_(_Global_critical_region_) VOID FatFlushAndCleanVolume( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVCB Vcb, IN FAT_FLUSH_TYPE FlushType ); BOOLEAN FatIsBootSectorFat ( IN PPACKED_BOOT_SECTOR BootSector ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatLockVolumeInternal ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject OPTIONAL ); NTSTATUS FatUnlockVolumeInternal ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject OPTIONAL ); // // Name support routines, implemented in NameSup.c // // // BOOLEAN // FatAreNamesEqual ( // IN PIRP_CONTEXT IrpContext, // IN OEM_STRING ConstantNameA, // IN OEM_STRING ConstantNameB // ) // // /*++ // // Routine Description: // // This routine simple returns whether the two names are exactly equal. // If the two names are known to be constant, this routine is much // faster than FatIsDbcsInExpression. // // Arguments: // // ConstantNameA - Constant name. // // ConstantNameB - Constant name. // // Return Value: // // BOOLEAN - TRUE if the two names are lexically equal. // #define FatAreNamesEqual(IRPCONTEXT,NAMEA,NAMEB) ( \ ((ULONG)(NAMEA).Length == (ULONG)(NAMEB).Length) && \ (RtlEqualMemory( &(NAMEA).Buffer[0], \ &(NAMEB).Buffer[0], \ (NAMEA).Length )) \ ) // // BOOLEAN // FatIsNameShortOemValid ( // IN PIRP_CONTEXT IrpContext, // IN OEM_STRING Name, // IN BOOLEAN CanContainWildCards, // IN BOOLEAN PathNamePermissible, // IN BOOLEAN LeadingBackslashPermissible // ) // // /*++ // // Routine Description: // // This routine scans the input name and verifies that if only // contains valid characters // // Arguments: // // Name - Supplies the input name to check. // // CanContainWildCards - Indicates if the name can contain wild cards // (i.e., * and ?). // // Return Value: // // BOOLEAN - Returns TRUE if the name is valid and FALSE otherwise. // // --*/ // // The FatIsNameLongOemValid and FatIsNameLongUnicodeValid are similar. // #define FatIsNameShortOemValid(IRPCONTEXT,NAME,CAN_CONTAIN_WILD_CARDS,PATH_NAME_OK,LEADING_BACKSLASH_OK) ( \ FsRtlIsFatDbcsLegal((NAME), \ (CAN_CONTAIN_WILD_CARDS), \ (PATH_NAME_OK), \ (LEADING_BACKSLASH_OK)) \ ) #define FatIsNameLongOemValid(IRPCONTEXT,NAME,CAN_CONTAIN_WILD_CARDS,PATH_NAME_OK,LEADING_BACKSLASH_OK) ( \ FsRtlIsHpfsDbcsLegal((NAME), \ (CAN_CONTAIN_WILD_CARDS), \ (PATH_NAME_OK), \ (LEADING_BACKSLASH_OK)) \ ) static INLINE BOOLEAN FatIsNameLongUnicodeValid ( PIRP_CONTEXT IrpContext, PUNICODE_STRING Name, BOOLEAN CanContainWildcards, BOOLEAN PathNameOk, BOOLEAN LeadingBackslashOk ) { ULONG i; UNREFERENCED_PARAMETER( IrpContext ); UNREFERENCED_PARAMETER( LeadingBackslashOk ); UNREFERENCED_PARAMETER( PathNameOk ); // // I'm not bothering to do the whole thing, just enough to make this call look // the same as the others. // NT_ASSERT( !PathNameOk && !LeadingBackslashOk ); for (i=0; i < Name->Length/sizeof(WCHAR); i++) { if ((Name->Buffer[i] < 0x80) && !(FsRtlIsAnsiCharacterLegalHpfs(Name->Buffer[i], CanContainWildcards))) { return FALSE; } } return TRUE; } BOOLEAN FatIsNameInExpression ( IN PIRP_CONTEXT IrpContext, IN OEM_STRING Expression, IN OEM_STRING Name ); VOID FatStringTo8dot3 ( _In_ PIRP_CONTEXT IrpContext, _In_ OEM_STRING InputString, _Out_writes_bytes_(11) PFAT8DOT3 Output8dot3 ); VOID Fat8dot3ToString ( _In_ PIRP_CONTEXT IrpContext, _In_ PDIRENT Dirent, _In_ BOOLEAN RestoreCase, _Out_ POEM_STRING OutputString ); _Requires_lock_held_(_Global_critical_region_) VOID FatGetUnicodeNameFromFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN OUT PUNICODE_STRING Lfn ); _Requires_lock_held_(_Global_critical_region_) VOID FatSetFullFileNameInFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); VOID FatSetFullNameInFcb ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFCB Fcb, _In_ PUNICODE_STRING FinalName ); VOID FatUnicodeToUpcaseOem ( IN PIRP_CONTEXT IrpContext, IN POEM_STRING OemString, IN PUNICODE_STRING UnicodeString ); _Requires_lock_held_(_Global_critical_region_) VOID FatSelectNames ( IN PIRP_CONTEXT IrpContext, IN PDCB Parent, IN POEM_STRING OemName, IN PUNICODE_STRING UnicodeName, IN OUT POEM_STRING ShortName, IN PUNICODE_STRING SuggestedShortName OPTIONAL, IN OUT BOOLEAN *AllLowerComponent, IN OUT BOOLEAN *AllLowerExtension, IN OUT BOOLEAN *CreateLfn ); VOID FatEvaluateNameCase ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING Name, IN OUT BOOLEAN *AllLowerComponent, IN OUT BOOLEAN *AllLowerExtension, IN OUT BOOLEAN *CreateLfn ); BOOLEAN FatSpaceInName ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING UnicodeName ); VOID FatUnicodeRestoreShortNameCase( IN PUNICODE_STRING ShortNameWithCase, IN BOOLEAN LowerCase8, IN BOOLEAN LowerCase3 ); // // Resources support routines/macros, implemented in ResrcSup.c // // The following routines/macros are used for gaining shared and exclusive // access to the global/vcb data structures. The routines are implemented // in ResrcSup.c. There is a global resources that everyone tries to take // out shared to do their work, with the exception of mount/dismount which // take out the global resource exclusive. All other resources only work // on their individual item. For example, an Fcb resource does not take out // a Vcb resource. But the way the file system is structured we know // that when we are processing an Fcb other threads cannot be trying to remove // or alter the Fcb, so we do not need to acquire the Vcb. // // The procedures/macros are: // // Macro FatData Vcb Fcb Subsequent macros // // AcquireExclusiveGlobal Read/Write None None ReleaseGlobal // // AcquireSharedGlobal Read None None ReleaseGlobal // // AcquireExclusiveVcb Read Read/Write None ReleaseVcb // // AcquireSharedVcb Read Read None ReleaseVcb // // AcquireExclusiveFcb Read None Read/Write ConvertToSharFcb // ReleaseFcb // // AcquireSharedFcb Read None Read ReleaseFcb // // ConvertToSharedFcb Read None Read ReleaseFcb // // ReleaseGlobal // // ReleaseVcb // // ReleaseFcb // // // FINISHED // FatAcquireExclusiveGlobal ( // IN PIRP_CONTEXT IrpContext // ); // // FINISHED // FatAcquireSharedGlobal ( // IN PIRP_CONTEXT IrpContext // ); // #define FatAcquireExclusiveGlobal(IRPCONTEXT) ( \ ExAcquireResourceExclusiveLite( &FatData.Resource, BooleanFlagOn((IRPCONTEXT)->Flags, IRP_CONTEXT_FLAG_WAIT) ) \ ) #define FatAcquireSharedGlobal(IRPCONTEXT) ( \ ExAcquireResourceSharedLite( &FatData.Resource, BooleanFlagOn((IRPCONTEXT)->Flags, IRP_CONTEXT_FLAG_WAIT) ) \ ) // // The following macro must only be called when Wait is TRUE! // // FatAcquireExclusiveVolume ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb // ); // // FatReleaseVolume ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb // ); // #define FatAcquireExclusiveVolume(IRPCONTEXT,VCB) { \ PFCB __FFFFFcb = NULL; \ NT_ASSERT(FlagOn((IRPCONTEXT)->Flags, IRP_CONTEXT_FLAG_WAIT)); \ (VOID)FatAcquireExclusiveVcb( (IRPCONTEXT), (VCB) ); \ while ( (__FFFFFcb = FatGetNextFcbBottomUp((IRPCONTEXT), __FFFFFcb, (VCB)->RootDcb)) != NULL) { \ (VOID)FatAcquireExclusiveFcb((IRPCONTEXT), __FFFFFcb ); \ } \ } #define FatReleaseVolume(IRPCONTEXT,VCB) { \ PFCB __FFFFFcb = NULL; \ NT_ASSERT(FlagOn((IRPCONTEXT)->Flags, IRP_CONTEXT_FLAG_WAIT)); \ while ( (__FFFFFcb = FatGetNextFcbBottomUp((IRPCONTEXT), __FFFFFcb, (VCB)->RootDcb)) != NULL) { \ (VOID)ExReleaseResourceLite( __FFFFFcb->Header.Resource ); \ } \ FatReleaseVcb((IRPCONTEXT), (VCB)); \ } // // Macro to enable easy tracking of Vcb state transitions. // #ifdef FASTFATDBG #define FatSetVcbCondition( V, X) { \ DebugTrace(0,DEBUG_TRACE_VERFYSUP,"%d -> ",(V)->VcbCondition); \ DebugTrace(0,DEBUG_TRACE_VERFYSUP,"%x\n",(X)); \ (V)->VcbCondition = (X); \ } #else #define FatSetVcbCondition( V, X) (V)->VcbCondition = (X) #endif // // These macros can be used to determine what kind of FAT we have for an // initialized Vcb. It is somewhat more elegant to use these (visually). // #define FatIsFat32(VCB) ((BOOLEAN)((VCB)->AllocationSupport.FatIndexBitSize == 32)) #define FatIsFat16(VCB) ((BOOLEAN)((VCB)->AllocationSupport.FatIndexBitSize == 16)) #define FatIsFat12(VCB) ((BOOLEAN)((VCB)->AllocationSupport.FatIndexBitSize == 12)) _Requires_lock_held_(_Global_critical_region_) _When_(return != FALSE && NoOpCheck != FALSE, _Acquires_exclusive_lock_(Vcb->Resource)) FINISHED FatAcquireExclusiveVcb_Real ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN NoOpCheck ); #define FatAcquireExclusiveVcb( IC, V) FatAcquireExclusiveVcb_Real( IC, V, FALSE) #define FatAcquireExclusiveVcbNoOpCheck( IC, V) FatAcquireExclusiveVcb_Real( IC, V, TRUE) _Requires_lock_held_(_Global_critical_region_) _When_(return != 0, _Acquires_shared_lock_(Vcb->Resource)) FINISHED FatAcquireSharedVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); _Requires_lock_held_(_Global_critical_region_) _Acquires_exclusive_lock_(*Fcb->Header.Resource) FINISHED FatAcquireExclusiveFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); _Requires_lock_held_(_Global_critical_region_) _Acquires_shared_lock_(*Fcb->Header.Resource) FINISHED FatAcquireSharedFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); _Requires_lock_held_(_Global_critical_region_) _When_(return != 0, _Acquires_shared_lock_(*Fcb->Header.Resource)) FINISHED FatAcquireSharedFcbWaitForEx ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); #define FatVcbAcquiredExclusive(IRPCONTEXT,VCB) ( \ ExIsResourceAcquiredExclusiveLite(&(VCB)->Resource) || \ ExIsResourceAcquiredExclusiveLite(&FatData.Resource) \ ) #define FatFcbAcquiredShared(IRPCONTEXT,FCB) ( \ ExIsResourceAcquiredSharedLite((FCB)->Header.Resource) \ ) #define FatFcbAcquiredExclusive(IRPCONTEXT,FCB) ( \ ExIsResourceAcquiredExclusiveLite((FCB)->Header.Resource) \ ) #define FatAcquireDirectoryFileMutex(VCB) { \ NT_ASSERT(KeAreApcsDisabled()); \ ExAcquireFastMutexUnsafe(&(VCB)->DirectoryFileCreationMutex); \ } #define FatReleaseDirectoryFileMutex(VCB) { \ NT_ASSERT(KeAreApcsDisabled()); \ ExReleaseFastMutexUnsafe(&(VCB)->DirectoryFileCreationMutex); \ } // // The following are cache manager call backs BOOLEAN FatAcquireVolumeForClose ( IN PVOID Vcb, IN BOOLEAN Wait ); VOID FatReleaseVolumeFromClose ( IN PVOID Vcb ); _Requires_lock_held_(_Global_critical_region_) BOOLEAN NTAPI FatAcquireFcbForLazyWrite ( IN PVOID Null, IN BOOLEAN Wait ); _Requires_lock_held_(_Global_critical_region_) VOID NTAPI FatReleaseFcbFromLazyWrite ( IN PVOID Null ); _Requires_lock_held_(_Global_critical_region_) BOOLEAN NTAPI FatAcquireFcbForReadAhead ( IN PVOID Null, IN BOOLEAN Wait ); _Requires_lock_held_(_Global_critical_region_) VOID NTAPI FatReleaseFcbFromReadAhead ( IN PVOID Null ); _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH) _Requires_lock_held_(_Global_critical_region_) NTSTATUS NTAPI FatAcquireForCcFlush ( IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject ); _Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH) _Requires_lock_held_(_Global_critical_region_) NTSTATUS NTAPI FatReleaseForCcFlush ( IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject ); BOOLEAN NTAPI FatNoOpAcquire ( IN PVOID Fcb, IN BOOLEAN Wait ); VOID NTAPI FatNoOpRelease ( IN PVOID Fcb ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS NTAPI FatFilterCallbackAcquireForCreateSection ( IN PFS_FILTER_CALLBACK_DATA CallbackData, OUT PVOID *CompletionContext ); // // VOID // FatConvertToSharedFcb ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // #define FatConvertToSharedFcb(IRPCONTEXT,Fcb) { \ ExConvertExclusiveToSharedLite( (Fcb)->Header.Resource ); \ } // // VOID // FatReleaseGlobal ( // IN PIRP_CONTEXT IrpContext // ); // // VOID // FatReleaseVcb ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb // ); // // VOID // FatReleaseFcb ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb // ); // #define FatDeleteResource(RESRC) { \ ExDeleteResourceLite( (RESRC) ); \ } #define FatReleaseGlobal(IRPCONTEXT) { \ ExReleaseResourceLite( &(FatData.Resource) ); \ } #define FatReleaseVcb(IRPCONTEXT,Vcb) { \ ExReleaseResourceLite( &((Vcb)->Resource) ); \ } #define FatReleaseFcb(IRPCONTEXT,Fcb) { \ ExReleaseResourceLite( (Fcb)->Header.Resource ); \ } // // 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 FatGetFcbOplock(F) &(F)->Header.Oplock #else #define FatGetFcbOplock(F) &(F)->Specific.Fcb.Oplock #endif // // In-memory structure support routine, implemented in StrucSup.c // _Requires_lock_held_(_Global_critical_region_) VOID FatInitializeVcb ( IN PIRP_CONTEXT IrpContext, IN OUT PVCB Vcb, IN PDEVICE_OBJECT TargetDeviceObject, IN PVPB Vpb, IN PDEVICE_OBJECT FsDeviceObject ); VOID FatTearDownVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); VOID FatDeleteVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatCreateRootDcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); PFCB FatCreateFcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PDCB ParentDcb, IN ULONG LfnOffsetWithinDirectory, IN ULONG DirentOffsetWithinDirectory, IN PDIRENT Dirent, IN PUNICODE_STRING Lfn OPTIONAL, IN PUNICODE_STRING OrigLfn OPTIONAL, IN BOOLEAN IsPagingFile, IN BOOLEAN SingleResource ); PDCB FatCreateDcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PDCB ParentDcb, IN ULONG LfnOffsetWithinDirectory, IN ULONG DirentOffsetWithinDirectory, IN PDIRENT Dirent, IN PUNICODE_STRING Lfn OPTIONAL ); VOID FatDeleteFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB *Fcb ); PCCB FatCreateCcb ( IN PIRP_CONTEXT IrpContext ); VOID FatDeallocateCcbStrings( IN PCCB Ccb ); VOID FatDeleteCcb ( IN PIRP_CONTEXT IrpContext, IN PCCB *Ccb ); PIRP_CONTEXT FatCreateIrpContext ( IN PIRP Irp, IN BOOLEAN Wait ); VOID FatDeleteIrpContext_Real ( IN PIRP_CONTEXT IrpContext ); #ifdef FASTFATDBG #define FatDeleteIrpContext(IRPCONTEXT) { \ FatDeleteIrpContext_Real((IRPCONTEXT)); \ (IRPCONTEXT) = NULL; \ } #else #define FatDeleteIrpContext(IRPCONTEXT) { \ FatDeleteIrpContext_Real((IRPCONTEXT)); \ } #endif // FASTFAT_DBG PFCB FatGetNextFcbTopDown ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PFCB TerminationFcb ); PFCB FatGetNextFcbBottomUp ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PFCB TerminationFcb ); // // These two macros just make the code a bit cleaner. // #define FatGetFirstChild(DIR) ((PFCB)( \ IsListEmpty(&(DIR)->Specific.Dcb.ParentDcbQueue) ? NULL : \ CONTAINING_RECORD((DIR)->Specific.Dcb.ParentDcbQueue.Flink, \ DCB, \ ParentDcbLinks.Flink))) #define FatGetNextSibling(FILE) ((PFCB)( \ &(FILE)->ParentDcb->Specific.Dcb.ParentDcbQueue.Flink == \ (PVOID)(FILE)->ParentDcbLinks.Flink ? NULL : \ CONTAINING_RECORD((FILE)->ParentDcbLinks.Flink, \ FCB, \ ParentDcbLinks.Flink))) _Requires_lock_held_(_Global_critical_region_) BOOLEAN FatCheckForDismount ( IN PIRP_CONTEXT IrpContext, PVCB Vcb, IN BOOLEAN Force ); VOID FatConstructNamesInFcb ( IN PIRP_CONTEXT IrpContext, PFCB Fcb, PDIRENT Dirent, PUNICODE_STRING Lfn OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) VOID FatCheckFreeDirentBitmap ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb ); ULONG FatVolumeUncleanCount ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); VOID FatPreallocateCloseContext ( IN PVCB Vcb ); PCLOSE_CONTEXT FatAllocateCloseContext( IN PVCB Vcb ); // // BOOLEAN // FatIsRawDevice ( // IN PIRP_CONTEXT IrpContext, // IN NTSTATUS Status // ); // #define FatIsRawDevice(IC,S) ( \ ((S) == STATUS_DEVICE_NOT_READY) || \ ((S) == STATUS_NO_MEDIA_IN_DEVICE) \ ) // // Routines to support managing file names Fcbs and Dcbs. // Implemented in SplaySup.c // VOID FatInsertName ( IN PIRP_CONTEXT IrpContext, IN PRTL_SPLAY_LINKS *RootNode, IN PFILE_NAME_NODE Name ); VOID FatRemoveNames ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); PFCB FatFindFcb ( IN PIRP_CONTEXT IrpContext, IN OUT PRTL_SPLAY_LINKS *RootNode, IN PSTRING Name, OUT PBOOLEAN FileNameDos OPTIONAL ); BOOLEAN FatIsHandleCountZero ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); typedef enum _COMPARISON { IsLessThan, IsGreaterThan, IsEqual } COMPARISON; COMPARISON FatCompareNames ( IN PSTRING NameA, IN PSTRING NameB ); // // Do a macro here to check for a common case. // #define CompareNames(NAMEA,NAMEB) ( \ *(PUCHAR)(NAMEA)->Buffer != *(PUCHAR)(NAMEB)->Buffer ? \ *(PUCHAR)(NAMEA)->Buffer < *(PUCHAR)(NAMEB)->Buffer ? \ IsLessThan : IsGreaterThan : \ FatCompareNames((PSTRING)(NAMEA), (PSTRING)(NAMEB)) \ ) // // Time conversion support routines, implemented in TimeSup.c // _Success_(return != FALSE) BOOLEAN FatNtTimeToFatTime ( _In_ PIRP_CONTEXT IrpContext, _In_ PLARGE_INTEGER NtTime, _In_ BOOLEAN Rounding, _Out_ PFAT_TIME_STAMP FatTime, _Out_opt_ PUCHAR TenMsecs ); LARGE_INTEGER FatFatTimeToNtTime ( _In_ PIRP_CONTEXT IrpContext, _In_ FAT_TIME_STAMP FatTime, _In_ UCHAR TenMilliSeconds ); LARGE_INTEGER FatFatDateToNtTime ( _In_ PIRP_CONTEXT IrpContext, _In_ FAT_DATE FatDate ); FAT_TIME_STAMP FatGetCurrentFatTime ( _In_ PIRP_CONTEXT IrpContext ); // // Low level verification routines, implemented in VerfySup.c // // The first routine is called to help process a verify IRP. Its job is // to walk every Fcb/Dcb and mark them as need to be verified. // // The other routines are used by every dispatch routine to verify that // an Vcb/Fcb/Dcb is still good. The routine walks as much of the opened // file/directory tree as necessary to make sure that the path is still valid. // The function result indicates if the procedure needed to block for I/O. // If the structure is bad the procedure raise the error condition // STATUS_FILE_INVALID, otherwise they simply return to their caller // typedef enum _FAT_VOLUME_STATE { VolumeClean, VolumeDirty, VolumeDirtyWithSurfaceTest } FAT_VOLUME_STATE, *PFAT_VOLUME_STATE; VOID FatMarkFcbCondition ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN FCB_CONDITION FcbCondition, IN BOOLEAN Recursive ); VOID FatVerifyVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); _Requires_lock_held_(_Global_critical_region_) VOID FatVerifyFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); KDEFERRED_ROUTINE FatCleanVolumeDpc; VOID NTAPI FatCleanVolumeDpc ( _In_ PKDPC Dpc, _In_opt_ PVOID DeferredContext, _In_opt_ PVOID SystemArgument1, _In_opt_ PVOID SystemArgument2 ); _Requires_lock_held_(_Global_critical_region_) VOID FatMarkVolume ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN FAT_VOLUME_STATE VolumeState ); WORKER_THREAD_ROUTINE FatFspMarkVolumeDirtyWithRecover; VOID NTAPI FatFspMarkVolumeDirtyWithRecover ( PVOID Parameter ); VOID FatCheckDirtyBit ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); VOID FatQuickVerifyVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); VOID FatVerifyOperationIsLegal ( IN PIRP_CONTEXT IrpContext ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatPerformVerify ( _In_ PIRP_CONTEXT IrpContext, _In_ PIRP Irp, _In_ PDEVICE_OBJECT Device ); // // Work queue routines for posting and retrieving an Irp, implemented in // workque.c // VOID NTAPI FatOplockComplete ( IN PVOID Context, IN PIRP Irp ); VOID NTAPI FatPrePostIrp ( IN PVOID Context, IN PIRP Irp ); VOID #ifdef __REACTOS__ NTAPI #endif FatAddToWorkque ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS FatFsdPostRequest ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); // // Miscellaneous support routines // // // ULONG // PtrOffset ( // IN PVOID BasePtr, // IN PVOID OffsetPtr // ); // #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 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; // // 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)); \ } #define CopyU4char(Dst,Src) { \ *((UNALIGNED UCHAR4 *)(Dst)) = *((UCHAR4 *)(Src)); \ } // // VOID // FatNotifyReportChange ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb, // IN PFCB Fcb, // IN ULONG Filter, // IN ULONG Action // ); // #define FatNotifyReportChange(I,V,F,FL,A) { \ if ((F)->FullFileName.Buffer == NULL) { \ FatSetFullFileNameInFcb((I),(F)); \ } \ NT_ASSERT( (F)->FullFileName.Length != 0 ); \ NT_ASSERT( (F)->FinalNameLength != 0 ); \ NT_ASSERT( (F)->FullFileName.Length > (F)->FinalNameLength ); \ NT_ASSERT( (F)->FullFileName.Buffer[((F)->FullFileName.Length - (F)->FinalNameLength)/sizeof(WCHAR) - 1] == L'\\' ); \ FsRtlNotifyFullReportChange( (V)->NotifySync, \ &(V)->DirNotifyList, \ (PSTRING)&(F)->FullFileName, \ (USHORT) ((F)->FullFileName.Length - \ (F)->FinalNameLength), \ (PSTRING)NULL, \ (PSTRING)NULL, \ (ULONG)FL, \ (ULONG)A, \ (PVOID)NULL ); \ } // // The FSD Level dispatch routines. These routines are called by the // I/O system via the dispatch table in the Driver Object. // // They each accept as input a pointer to a device object (actually most // expect a volume device object, with the exception of the file system // control function which can also take a file system device object), and // a pointer to the IRP. They either perform the function at the FSD level // or post the request to the FSP work queue for FSP level processing. // _Function_class_(IRP_MJ_CLEANUP) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdCleanup ( // implemented in Cleanup.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_CLOSE) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdClose ( // implemented in Close.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_CREATE) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdCreate ( // implemented in Create.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_DEVICE_CONTROL) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdDeviceControl ( // implemented in DevCtrl.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_DIRECTORY_CONTROL) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdDirectoryControl ( // implemented in DirCtrl.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_QUERY_EA) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdQueryEa ( // implemented in Ea.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_SET_EA) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdSetEa ( // implemented in Ea.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_QUERY_INFORMATION) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdQueryInformation ( // implemented in FileInfo.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_SET_INFORMATION) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdSetInformation ( // implemented in FileInfo.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_FLUSH_BUFFERS) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdFlushBuffers ( // implemented in Flush.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_FILE_SYSTEM_CONTROL) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdFileSystemControl ( // implemented in FsCtrl.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_LOCK_CONTROL) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdLockControl ( // implemented in LockCtrl.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_PNP) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdPnp ( // implemented in Pnp.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_READ) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdRead ( // implemented in Read.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_SHUTDOWN) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdShutdown ( // implemented in Shutdown.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_QUERY_VOLUME_INFORMATION) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdQueryVolumeInformation ( // implemented in VolInfo.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_SET_VOLUME_INFORMATION) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdSetVolumeInformation ( // implemented in VolInfo.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); _Function_class_(IRP_MJ_WRITE) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI FatFsdWrite ( // implemented in Write.c _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ); // // 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(IRP) IoIsOperationSynchronous(Irp) // // 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. // WORKER_THREAD_ROUTINE FatFspDispatch; VOID NTAPI FatFspDispatch ( // implemented in FspDisp.c _In_ PVOID Context ); // // The following routines are the FSP work routines that are called // by the preceding FatFspDispath routine. Each takes as input a pointer // to the IRP, perform the function, and return a pointer to the volume // device object that they just finished servicing (if any). The return // pointer is then used by the main Fsp dispatch routine to check for // additional IRPs in the volume's overflow queue. // // Each of the following routines is also responsible for completing the IRP. // We moved this responsibility from the main loop to the individual routines // to allow them the ability to complete the IRP and continue post processing // actions. // _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonCleanup ( // implemented in Cleanup.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonClose ( // implemented in Close.c IN PVCB Vcb, IN PFCB Fcb, IN PCCB Ccb, IN TYPE_OF_OPEN TypeOfOpen, IN BOOLEAN Wait, IN BOOLEAN TopLevel, OUT PBOOLEAN VcbDeleted OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) VOID FatFspClose ( // implemented in Close.c IN PVCB Vcb OPTIONAL ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonCreate ( // implemented in Create.c _Inout_ PIRP_CONTEXT IrpContext, _Inout_ PIRP Irp ); #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonCreateOnNewStack ( // implemented in Create.c _Inout_ PIRP_CONTEXT IrpContext, _Inout_ PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) VOID FatCommonCreateCallout ( // implemented in Create.c _In_ PFAT_CALLOUT_PARAMETERS CalloutParameters ); #endif _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonDirectoryControl ( // implemented in DirCtrl.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonDeviceControl ( // implemented in DevCtrl.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS FatCommonQueryEa ( // implemented in Ea.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS FatCommonSetEa ( // implemented in Ea.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonQueryInformation ( // implemented in FileInfo.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonSetInformation ( // implemented in FileInfo.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonFlushBuffers ( // implemented in Flush.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonFileSystemControl ( // implemented in FsCtrl.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonLockControl ( // implemented in LockCtrl.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonPnp ( // implemented in Pnp.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonRead ( // implemented in Read.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonShutdown ( // implemented in Shutdown.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonQueryVolumeInfo ( // implemented in VolInfo.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonSetVolumeInfo ( // implemented in VolInfo.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatCommonWrite ( // implemented in Write.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); // // The following is implemented in Flush.c, and does what is says. // _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatFlushFile ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN FAT_FLUSH_TYPE FlushType ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatFlushDirectory ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN FAT_FLUSH_TYPE FlushType ); NTSTATUS FatFlushFat ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatFlushVolume ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN FAT_FLUSH_TYPE FlushType ); NTSTATUS FatHijackIrpAndFlushDevice ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PDEVICE_OBJECT TargetDeviceObject ); VOID FatFlushFatEntries ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG Cluster, IN ULONG Count ); VOID FatFlushDirentForFile ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); // // The following procedure is used by the FSP and FSD routines to complete // an IRP. // // Note that this macro allows either the Irp or the IrpContext to be // null, however the only legal order to do this in is: // // FatCompleteRequest( NULL, Irp, Status ); // completes Irp & preserves context // ... // FatCompleteRequest( IrpContext, NULL, DontCare ); // deallocates context // // This would typically be done in order to pass a "naked" IrpContext off to // the Fsp for post processing, such as read ahead. // VOID FatCompleteRequest_Real ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN NTSTATUS Status ); #define FatCompleteRequest(IRPCONTEXT,IRP,STATUS) { \ FatCompleteRequest_Real(IRPCONTEXT,IRP,STATUS); \ } BOOLEAN FatIsIrpTopLevel ( IN PIRP Irp ); // // The Following routine makes a popup // _Requires_lock_held_(_Global_critical_region_) VOID FatPopUpFileCorrupt ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); // // Here are the callbacks used by the I/O system for checking for fast I/O or // doing a fast query info call, or doing fast lock calls. // _Function_class_(FAST_IO_CHECK_IF_POSSIBLE) BOOLEAN NTAPI FatFastIoCheckIfPossible ( 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 ); _Function_class_(FAST_IO_QUERY_BASIC_INFO) BOOLEAN NTAPI FatFastQueryBasicInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN OUT PFILE_BASIC_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); _Function_class_(FAST_IO_QUERY_STANDARD_INFO) BOOLEAN NTAPI FatFastQueryStdInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN OUT PFILE_STANDARD_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO) BOOLEAN NTAPI FatFastQueryNetworkOpenInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); _Function_class_(FAST_IO_LOCK) BOOLEAN NTAPI FatFastLock ( 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 ); _Function_class_(FAST_IO_UNLOCK_SINGLE) BOOLEAN NTAPI FatFastUnlockSingle ( 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 ); _Function_class_(FAST_IO_UNLOCK_ALL) BOOLEAN NTAPI FatFastUnlockAll ( IN PFILE_OBJECT FileObject, PEPROCESS ProcessId, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); _Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY) BOOLEAN NTAPI FatFastUnlockAllByKey ( IN PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); VOID FatExamineFatEntries( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG StartIndex OPTIONAL, IN ULONG EndIndex OPTIONAL, IN BOOLEAN SetupWindows, IN PFAT_WINDOW SwitchToWindow OPTIONAL, IN PULONG BitMapBuffer OPTIONAL ); BOOLEAN FatScanForDataTrack( IN PIRP_CONTEXT IrpContext, IN PDEVICE_OBJECT TargetDeviceObject ); // // The following macro is used to determine is a file has been deleted. // // BOOLEAN // IsFileDeleted ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // #define IsFileDeleted(IRPCONTEXT,FCB) \ (FlagOn((FCB)->FcbState, FCB_STATE_DELETE_ON_CLOSE) && \ ((FCB)->UncleanCount == 0)) // // The following macro is used by the dispatch routines to determine if // an operation is to be done with or without Write Through. // // BOOLEAN // IsFileWriteThrough ( // IN PFILE_OBJECT FileObject, // IN PVCB Vcb // ); // #define IsFileWriteThrough(FO,VCB) ( \ BooleanFlagOn((FO)->Flags, FO_WRITE_THROUGH) \ ) // // The following macro is used to set the is fast i/o possible field in // the common part of the nonpaged fcb. It checks that this is actually // an FCB (as opposed to a DCB) so that directory oplock code works properly. // // // BOOLEAN // FatIsFastIoPossible ( // IN PFCB Fcb // ); // #define FatIsFastIoPossible(FCB) ((BOOLEAN) \ ((((FCB)->FcbCondition != FcbGood) || \ (NodeType( (FCB) ) != FAT_NTC_FCB) || \ !FsRtlOplockIsFastIoPossible( FatGetFcbOplock(FCB) )) ? \ FastIoIsNotPossible \ : \ (!FsRtlAreThereCurrentFileLocks( &(FCB)->Specific.Fcb.FileLock ) && \ ((FCB)->NonPaged->OutstandingAsyncWrites == 0) && \ !FlagOn( (FCB)->Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED ) ? \ FastIoIsPossible \ : \ FastIoIsQuestionable \ ) \ ) \ ) #if (NTDDI_VERSION >= NTDDI_WIN8) // // Detect whether this file can have an oplock on it. As of Windows 8 file and // directories can have oplocks. // #define FatIsNodeTypeOplockable(N) ( \ ((N) == FAT_NTC_FCB) || \ ((N) == FAT_NTC_ROOT_DCB) || \ ((N) == FAT_NTC_DCB) \ ) #else #define FatIsNodeTypeOplockable(N) ( \ ((N) == FAT_NTC_FCB) \ ) #endif #define FatIsFileOplockable(F) ( \ FatIsNodeTypeOplockable( NodeType( (F) )) \ ) // // The following macro is used to detemine if the file object is opened // for read only access (i.e., it is not also opened for write access or // delete access). // // BOOLEAN // IsFileObjectReadOnly ( // IN PFILE_OBJECT FileObject // ); // #define IsFileObjectReadOnly(FO) (!((FO)->WriteAccess | (FO)->DeleteAccess)) // // The following two macro are used by the Fsd/Fsp exception handlers to // process an exception. The first macro is the exception filter used in the // Fsd/Fsp to decide if an exception should be handled at this level. // The second macro decides if the exception is to be finished off by // completing the IRP, and cleaning up the Irp Context, or if we should // bugcheck. Exception values such as STATUS_FILE_INVALID (raised by // VerfySup.c) cause us to complete the Irp and cleanup, while exceptions // such as accvio cause us to bugcheck. // // The basic structure for fsd/fsp exception handling is as follows: // // FatFsdXxx(...) // { // try { // // ... // // } except(FatExceptionFilter( IrpContext, GetExceptionCode() )) { // // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); // } // // Return Status; // } // // To explicitly raise an exception that we expect, such as // STATUS_FILE_INVALID, use the below macro FatRaiseStatus(). To raise a // status from an unknown origin (such as CcFlushCache()), use the macro // FatNormalizeAndRaiseStatus. This will raise the status if it is expected, // or raise STATUS_UNEXPECTED_IO_ERROR if it is not. // // If we are vicariously handling exceptions without using FatProcessException(), // if there is the possibility that we raised that exception, one *must* // reset the IrpContext so a subsequent raise in the course of handling this // request that is *not* explicit, i.e. like a pagein error, does not get // spoofed into believing that the first raise status is the reason the second // occured. This could have really serious consequences. // // It is an excellent idea to always FatResetExceptionState in these cases. // // Note that when using these two macros, the original status is placed in // IrpContext->ExceptionStatus, signaling FatExceptionFilter and // FatProcessException that the status we actually raise is by definition // expected. // ULONG FatExceptionFilter ( IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer ); #if DBG ULONG FatBugCheckExceptionFilter ( IN PEXCEPTION_POINTERS ExceptionPointer ); #endif _Requires_lock_held_(_Global_critical_region_) NTSTATUS FatProcessException ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN NTSTATUS ExceptionCode ); // // VOID // FatRaiseStatus ( // IN PRIP_CONTEXT IrpContext, // IN NT_STATUS Status // ); // // #if DBG #ifdef _MSC_VER #define DebugBreakOnStatus(S) { \ __pragma(warning(push)) \ __pragma(warning(disable:4127)) \ if (FatTestRaisedStatus) { \ if ((S) == STATUS_DISK_CORRUPT_ERROR || (S) == STATUS_FILE_CORRUPT_ERROR) { \ __pragma(warning(pop)) \ DbgPrint( "FAT: Breaking on interesting raised status (0x%08x)\n", (S) );\ DbgPrint( "FAT: Set FatTestRaisedStatus @ 0x%p to 0 to disable\n", \ &FatTestRaisedStatus ); \ NT_ASSERT(FALSE); \ } \ } \ } #else #define DebugBreakOnStatus(S) { \ if (FatTestRaisedStatus) { \ if ((S) == STATUS_DISK_CORRUPT_ERROR || (S) == STATUS_FILE_CORRUPT_ERROR) { \ DbgPrint( "FAT: Breaking on interesting raised status (0x%08x)\n", (S) );\ DbgPrint( "FAT: Set FatTestRaisedStatus @ 0x%p to 0 to disable\n", \ &FatTestRaisedStatus ); \ NT_ASSERT(FALSE); \ } \ } \ } #endif #else #define DebugBreakOnStatus(S) #endif #define FatRaiseStatus(IRPCONTEXT,STATUS) { \ (IRPCONTEXT)->ExceptionStatus = (STATUS); \ DebugBreakOnStatus( (STATUS) ) \ ExRaiseStatus( (STATUS) ); \ } #define FatResetExceptionState( IRPCONTEXT ) { \ (IRPCONTEXT)->ExceptionStatus = STATUS_SUCCESS; \ } // // VOID // FatNormalAndRaiseStatus ( // IN PRIP_CONTEXT IrpContext, // IN NT_STATUS Status // ); // #define FatNormalizeAndRaiseStatus(IRPCONTEXT,STATUS) { \ (IRPCONTEXT)->ExceptionStatus = (STATUS); \ ExRaiseStatus(FsRtlNormalizeNtstatus((STATUS),STATUS_UNEXPECTED_IO_ERROR)); \ } // // 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; _SEH2_LEAVE; } CLUSTER_TYPE FatInterpretClusterType ( IN PVCB Vcb, IN FAT_ENTRY Entry ); // // These routines define the FileId for FAT. Lacking a fixed/uniquifiable // notion, we simply come up with one which is unique in a given snapshot // of the volume. As long as the parent directory is not moved or compacted, // it may even be permanent. // // // The internal information used to identify the fcb/dcb on the // volume is the byte offset of the dirent of the file on disc. // Our root always has fileid 0. FAT32 roots are chains and can // use the LBO of the cluster, 12/16 roots use the lbo in the Vcb. // #define FatGenerateFileIdFromDirentOffset(ParentDcb,DirentOffset) \ ((ParentDcb) ? ((NodeType(ParentDcb) != FAT_NTC_ROOT_DCB || FatIsFat32((ParentDcb)->Vcb)) ? \ FatGetLboFromIndex( (ParentDcb)->Vcb, \ (ParentDcb)->FirstClusterOfFile ) : \ (ParentDcb)->Vcb->AllocationSupport.RootDirectoryLbo) + \ (DirentOffset) \ : \ 0) // // #define FatGenerateFileIdFromFcb(Fcb) \ FatGenerateFileIdFromDirentOffset( (Fcb)->ParentDcb, (Fcb)->DirentOffsetWithinDirectory ) // // Wrap to handle the ./.. cases appropriately. Note that we commute NULL parent to 0. This would // only occur in an illegal root ".." entry. // #define FATDOT ((ULONG)0x2020202E) #define FATDOTDOT ((ULONG)0x20202E2E) #define FatGenerateFileIdFromDirentAndOffset(Dcb,Dirent,DirentOffset) \ ((*((PULONG)(Dirent)->FileName)) == FATDOT ? FatGenerateFileIdFromFcb(Dcb) : \ ((*((PULONG)(Dirent)->FileName)) == FATDOTDOT ? ((Dcb)->ParentDcb ? \ FatGenerateFileIdFromFcb((Dcb)->ParentDcb) : \ 0) : \ FatGenerateFileIdFromDirentOffset(Dcb,DirentOffset))) // // BOOLEAN // FatDeviceIsFatFsdo( // IN PDEVICE_OBJECT D // ); // // Evaluates to TRUE if the supplied device object is one of the file system devices // we created at initialisation. // #define FatDeviceIsFatFsdo( D) (((D) == FatData.DiskFileSystemDeviceObject) || ((D) == FatData.CdromFileSystemDeviceObject)) // // BlockAlign(): Aligns P on the next V boundary. // BlockAlignTruncate(): Aligns P on the prev V boundary. // #define BlockAlign(P,V) ((ASSERT( V != 0)), (((P)) + (V-1) & (0-(V)))) #define BlockAlignTruncate(P,V) ((P) & (0-(V))) #define IsDirectory(FcbOrDcb) ((NodeType((FcbOrDcb)) == FAT_NTC_DCB) || (NodeType((FcbOrDcb)) == FAT_NTC_ROOT_DCB)) #endif // _FATPROCS_