/*++ Copyright (c) 1989-2000 Microsoft Corporation Module Name: UdfProcs.h Abstract: This module defines all of the globally used procedures in the Udfs file system. // @@BEGIN_DDKSPLIT Author: Dan Lovinger [DanLo] 29-May-1996 Revision History: Tom Jolly [TomJolly] 1-March-2000 UDF 2.01 support // @@END_DDKSPLIT --*/ #ifndef _UDFPROCS_ #define _UDFPROCS_ #include #include #include #include #ifndef INLINE #define INLINE __inline #endif #include "nodetype.h" #include "Udf.h" #include "UdfStruc.h" #include "UdfData.h" // // The Bug check file id for this module // #define BugCheckFileId (UDFS_BUG_CHECK_STRUCSUP) // // The local debug trace level // #define Dbg (UDFS_DEBUG_LEVEL_STRUCSUP) // // Miscellaneous support routines/macros // // // Yet another declaration of Min/Max // #ifndef Min #define Min(a, b) ((a) < (b) ? (a) : (b)) #endif #ifndef Max #define Max(a, b) ((a) > (b) ? (a) : (b)) #endif // // Yet another declaration of the basic bit fiddlers // #ifndef FlagMask #define FlagMask(F,SF) ( \ ((F) & (SF)) \ ) #endif //#ifndef BooleanFlagOn //#define BooleanFlagOn(F,SF) ( \ // (BOOLEAN)(FlagOn(F, SF) != 0) \ //) //#endif #ifndef BooleanFlagOff #define BooleanFlagOff(F,SF) ( \ (BOOLEAN)(FlagOn(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)((ULONG_PTR)(PTR) + (INC))) #define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG)(OFFSET) - (ULONG)(BASE))) // // Generic truncation/align/offset/remainder macros for power-of-two units. // // The offset and remainder functions range from zero to (unit - 1). The // re-offset in the remainder performs this work. // #define GenericTruncate(B, U) ( \ (B) & ~((U) - 1) \ ) #define GenericAlign(B, U) ( \ GenericTruncate((B) + (U) - 1, U) \ ) #define GenericOffset(B, U) ( \ (B) & ((U) - 1) \ ) #define GenericRemainder(B, U) ( \ GenericOffset( (U) - GenericOffset((B), (U)), (U) ) \ ) #define GenericTruncatePtr(B, U) ( \ (PVOID)(((ULONG_PTR)(B)) & ~((U) - 1)) \ ) #define GenericAlignPtr(B, U) ( \ GenericTruncatePtr((B) + (U) - 1, (U)) \ ) #define GenericOffsetPtr(B, U) ( \ (ULONG)(((ULONG_PTR)(B)) & ((U) - 1)) \ ) #define GenericRemainderPtr(B, U) ( \ (ULONG)GenericOffset( (U) - GenericOffsetPtr((B), (U)), (U) ) \ ) // // Useful compositions of the defaults for common types. // #define WordAlign(B) GenericAlign((B), 2) #define LongAlign(B) GenericAlign((B), 4) #define QuadAlign(B) GenericAlign((B), 8) #define WordOffset(B) GenericOffset((B), 2) #define LongOffset(B) GenericOffset((B), 4) #define QuadOffset(B) GenericOffset((B), 8) #define WordAlignPtr(P) GenericAlignPtr((P), 2) #define LongAlignPtr(P) GenericAlignPtr((P), 4) #define QuadAlignPtr(P) GenericAlignPtr((P), 8) #define WordOffsetPtr(P) GenericOffsetPtr((P), 2) #define LongOffsetPtr(P) GenericOffsetPtr((P), 4) #define QuadOffsetPtr(P) GenericOffsetPtr((P), 8) // // Macros to round up and down on sector and logical block boundaries. Although // UDF 1.01 specifies that a physical sector is the logical block size we will // be general and treat sectors and logical blocks as distinct. Since UDF may // at some point relax the restriction, these definitions will be the only // acknowledgement outside of the mount path (which merely checks the volume's // conformance). // // // Sector // #define SectorAlignN(SECTORSIZE, L) ( \ ((((ULONG)(L)) + ((SECTORSIZE) - 1)) & ~((SECTORSIZE) - 1)) \ ) #define SectorAlign(V, L) ( \ ((((ULONG)(L)) + (((V)->SectorSize) - 1)) & ~(((V)->SectorSize) - 1)) \ ) #define LlSectorAlign(V, L) ( \ ((((LONGLONG)(L)) + (((V)->SectorSize) - 1)) & ~(((LONGLONG)(V)->SectorSize) - 1)) \ ) #define SectorTruncate(V, L) ( \ ((ULONG)(L)) & ~(((V)->SectorSize) - 1) \ ) #define LlSectorTruncate(V, L) ( \ ((LONGLONG)(L)) & ~(((LONGLONG)(V)->SectorSize) - 1) \ ) #define BytesFromSectors(V, L) ( \ ((ULONG) (L)) << ((V)->SectorShift) \ ) #define SectorsFromBytes(V, L) ( \ ((ULONG) (L)) >> ((V)->SectorShift) \ ) #define LlBytesFromSectors(V, L) ( \ Int64ShllMod32( (ULONGLONG)(L), ((V)->SectorShift) ) \ ) #define LlSectorsFromBytes(V, L) ( \ Int64ShrlMod32( (ULONGLONG)(L), ((V)->SectorShift) ) \ ) #define SectorsFromBlocks(V, B) (B) #define SectorSize(V) ((V)->SectorSize) #define SectorOffset(V, L) ( \ ((ULONG) (L)) & (((V)->SectorSize) - 1) \ ) // // Logical Block // #define BlockAlignN(BLOCKSIZE, L) ( \ SectorAlighN((BLOCKSIZE), (L)) \ ) #define BlockAlign(V, L) ( \ SectorAlign((V), (L)) \ ) #define LlBlockAlign(V, L) ( \ LlSectorAlign((V), (L)) \ ) #define BlockTruncate(V, L) ( \ SectorTruncate((V), (L)) \ ) #define LlBlockTruncate(V, L) ( \ LlSectorTruncate((V), (L)) \ ) #define BytesFromBlocks(V, L) ( \ BytesFromSectors((V), (L)) \ ) #define BlocksFromBytes(V, L) ( \ SectorsFromBytes((V), (L)) \ ) #define LlBytesFromBlocks(V, L) ( \ LlBytesFromSectors((V), (L)) \ ) #define LlBlocksFromBytes(V, L) ( \ LlSectorsFromBytes((V), (L)) \ ) #define BlocksFromSectors(V, S) (S) #define BlockSize(V) (SectorSize(V)) #define BlockOffset(V, L) ( \ SectorOffset((V), (L)) \ ) // // The following types and macros are used to help unpack the packed and // misaligned fields found in various structures. // 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 word to a dst word, // performing an little/big endian swap. // #define SwapCopyUchar2(Dst,Src) { \ *((UNALIGNED UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src) + 1); \ *((UNALIGNED UCHAR1 *)(Dst) + 1) = *((UNALIGNED UCHAR1 *)(Src)); \ } // // This macro copies an unaligned src longword to an aligned dst longword // #define CopyUchar4(Dst,Src) { \ *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src)); \ } // // This macro copies an unaligned src longword to a dst longword, // performing an little/big endian swap. // #define SwapCopyUchar4(Dst,Src) { \ *((UNALIGNED UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src) + 3); \ *((UNALIGNED UCHAR1 *)(Dst) + 1) = *((UNALIGNED UCHAR1 *)(Src) + 2); \ *((UNALIGNED UCHAR1 *)(Dst) + 2) = *((UNALIGNED UCHAR1 *)(Src) + 1); \ *((UNALIGNED UCHAR1 *)(Dst) + 3) = *((UNALIGNED UCHAR1 *)(Src)); \ } // // 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));\ } // // 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 UdfIsFastIoPossible(F) ((BOOLEAN) \ ((((F)->Vcb->VcbCondition != VcbMounted ) || \ !FsRtlOplockIsFastIoPossible( &(F)->Oplock )) ? \ \ FastIoIsNotPossible : \ \ ((((F)->FileLock != NULL) && FsRtlAreThereCurrentFileLocks( (F)->FileLock )) ? \ \ FastIoIsQuestionable : \ \ FastIoIsPossible)) \ ) // // The following macros encapsulate the common work of raising exceptions while storing // the exception in the IrpContext. // INLINE DECLSPEC_NORETURN VOID UdfRaiseStatus ( IN PIRP_CONTEXT IrpContext, IN NTSTATUS Status ) { IrpContext->ExceptionStatus = Status; DebugBreakOnStatus( Status ); ExRaiseStatus( Status ); } INLINE VOID UdfNormalizeAndRaiseStatus ( IN PIRP_CONTEXT IrpContext, IN NTSTATUS Status ) { IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR ); ExRaiseStatus( IrpContext->ExceptionStatus ); } // // The following is a convenience macro to execute a little code before making // a shortcircuit out of a surrounding try-finally clause. This is usually to // set a status value. // // Note that our compilers support the leave keyword now and we don't have to // use the old try_exit: labels and goto. // #define try_leave(S) { S; leave; } // // 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 UdfPagedPool PagedPool #define UdfNonPagedPool NonPagedPool #define UdfNonPagedPoolCacheAligned NonPagedPoolCacheAligned // // Encapsulate safe pool freeing // INLINE VOID UdfFreePool( IN PVOID *Pool ) { if (*Pool != NULL) { ExFreePool(*Pool); *Pool = NULL; } } // // Encapsulate counted string compares with uncounted fields. Thanks to a // very smart compiler, we have to carefully tell it that no matter what it // thinks, it *cannot* do anything other than a bytewise compare. // INLINE BOOLEAN UdfEqualCountedString( IN PSTRING String, IN PCHAR Field ) { return (RtlEqualMemory( (CHAR UNALIGNED *)String->Buffer, (CHAR UNALIGNED *)Field, String->Length ) != 0); } // // Type of opens. FilObSup.c depends on this order. // typedef enum _TYPE_OF_OPEN { UnopenedFileObject = 0, StreamFileOpen, UserVolumeOpen, UserDirectoryOpen, UserFileOpen, BeyondValidType } TYPE_OF_OPEN, *PTYPE_OF_OPEN; // // Following routines handle entry in and out of the filesystem. They are // contained in UdfData.c. We also get some very generic utility functions // here that aren't associated with any particular datastructure. // NTSTATUS UdfFsdDispatch ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ); LONG UdfExceptionFilter ( IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer ); LONG UdfQueryDirExceptionFilter( IN PEXCEPTION_POINTERS ExceptionPointers ); NTSTATUS UdfProcessException ( IN PIRP_CONTEXT IrpContext OPTIONAL, IN PIRP Irp, IN NTSTATUS ExceptionCode ); VOID UdfCompleteRequest ( IN PIRP_CONTEXT IrpContext OPTIONAL, IN PIRP Irp OPTIONAL, IN NTSTATUS Status ); // // Following are the routines to handle the top level thread logic. // VOID UdfSetThreadContext ( IN PIRP_CONTEXT IrpContext, IN PTHREAD_CONTEXT ThreadContext ); INLINE VOID UdfRestoreThreadContext ( IN PIRP_CONTEXT IrpContext ) { IrpContext->ThreadContext->Udfs = 0; IoSetTopLevelIrp( IrpContext->ThreadContext->SavedTopLevelIrp ); IrpContext->ThreadContext = NULL; } // // Following are some generic utility functions we have to carry along for the ride // INLINE BOOLEAN UdfDeviceIsFsDo( IN PDEVICE_OBJECT Device ) { #if (NUMBER_OF_FS_OBJECTS != 2) #error "Size of fsdo array changed - fixme!" #endif return (Device == UdfData.FileSystemDeviceObjects[0]) || (Device == UdfData.FileSystemDeviceObjects[1]); } ULONG UdfSerial32 ( IN PCHAR Buffer, IN ULONG ByteCount ); VOID UdfInitializeCrc16 ( ULONG Polynomial ); USHORT UdfComputeCrc16 ( IN PUCHAR Buffer, IN ULONG ByteCount ); USHORT UdfComputeCrc16Uni ( PWCHAR Buffer, ULONG CharCount ); ULONG UdfHighBit ( ULONG Word ); // // Following are the fast entry points. // BOOLEAN UdfFastQueryBasicInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN OUT PFILE_BASIC_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); BOOLEAN UdfFastIoCheckIfPossible ( 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 UdfFastLock ( 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 UdfFastQueryNetworkInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); BOOLEAN UdfFastQueryStdInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN OUT PFILE_STANDARD_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); BOOLEAN UdfFastUnlockSingle ( 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 UdfFastUnlockAll ( IN PFILE_OBJECT FileObject, PEPROCESS ProcessId, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); BOOLEAN UdfFastUnlockAllByKey ( IN PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ); // // File access check routine, implemented in AcChkSup.c // INLINE BOOLEAN UdfIllegalFcbAccess ( IN PIRP_CONTEXT IrpContext, IN TYPE_OF_OPEN TypeOfOpen, IN ACCESS_MASK DesiredAccess ) /*++ Routine Description: This routine simply asserts that the access is legal for a readonly filesystem. Arguments: TypeOfOpen - type of open for the Fcb in question. DesiredAccess - mask of access the caller is trying for. Return Value: BOOLEAN True if illegal access, false otherwise. --*/ { return BooleanFlagOn( DesiredAccess, (TypeOfOpen != 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 ); } // // Sector lookup routines, implemented in AllocSup.c // BOOLEAN UdfLookupAllocation ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCCB Ccb, IN LONGLONG FileOffset, OUT PLONGLONG DiskOffset, OUT PULONG ByteCount ); VOID UdfDeletePcb ( IN PPCB Pcb ); NTSTATUS UdfInitializePcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN OUT PPCB *Pcb, IN PNSR_LVOL LVD ); VOID UdfAddToPcb ( IN PPCB Pcb, IN PNSR_PART PartitionDescriptor ); NTSTATUS UdfCompletePcb( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PPCB Pcb ); BOOLEAN UdfEquivalentPcb ( IN PIRP_CONTEXT IrpContext, IN PPCB Pcb1, IN PPCB Pcb2 ); ULONG UdfLookupPsnOfExtent ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN USHORT Reference, IN ULONG Lbn, IN ULONG Len ); ULONG UdfLookupMetaVsnOfExtent ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN USHORT Reference, IN ULONG Lbn, IN ULONG Len, IN BOOLEAN ExactEnd ); // // // Buffer control routines for data caching, implemented in CacheSup.c // VOID UdfCreateInternalStream ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFCB Fcb ); VOID UdfDeleteInternalStream ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); NTSTATUS UdfCompleteMdl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); typedef enum { METAMAPOP_INIT_VIEW_ONLY = 0, METAMAPOP_REMAP_VIEW, METAMAPOP_INIT_AND_MAP } MAPMETAOP; VOID UdfMapMetadataView ( IN PIRP_CONTEXT IrpContext, IN PMAPPED_PVIEW View, IN PVCB Vcb, IN USHORT Partition, IN ULONG Lbn, IN ULONG Length, IN MAPMETAOP Operation ); NTSTATUS UdfPurgeVolume ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN DismountUnderway ); // VOID // UdfUnpinView ( // IN PIRP_CONTEXT IrpContext, // IN PMAPPED_VIEW View // ); // // // Also releases the Vcb->VmcbMappingResource if the view was actually CcMapped. #define UdfUnpinView(IC,V) \ if (((V)->Bcb) != NULL) { \ CcUnpinData( ((V)->Bcb) ); \ UdfReleaseVmcb( (IC), (IC)->Vcb); \ ((V)->Bcb) = NULL; \ ((V)->View) = NULL; \ ((V)->Vsn) = UDF_INVALID_VSN; \ } // VOID // UdfUnpinData ( // IN PIRP_CONTEXT IrpContext, // IN OUT PBCB *Bcb // ); // #define UdfUnpinData(IC,B) \ if (*(B) != NULL) { CcUnpinData( *(B) ); *(B) = NULL; } // // Device I/O routines, implemented in DevIoSup.c // // These routines perform the actual device reads and other communcation. // They do not affect any data structures. // NTSTATUS UdfPerformDevIoCtrl ( 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 ); NTSTATUS UdfReadSectors ( IN PIRP_CONTEXT IrpContext, IN LONGLONG StartingOffset, IN ULONG ByteCount, IN BOOLEAN ReturnError, IN OUT PVOID Buffer, IN PDEVICE_OBJECT TargetDeviceObject ); NTSTATUS UdfNonCachedRead ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCCB Ccb, IN LONGLONG StartingOffset, IN ULONG ByteCount ); NTSTATUS UdfCreateUserMdl ( IN PIRP_CONTEXT IrpContext, IN ULONG BufferLength, IN BOOLEAN RaiseOnError, IN ULONG Operation ); VOID UdfWaitSync ( IN PIRP_CONTEXT IrpContext ); VOID UdfSingleAsync ( IN PIRP_CONTEXT IrpContext, IN LONGLONG ByteOffset, IN ULONG ByteCount ); // // VOID // UdfMapUserBuffer ( // IN PIRP_CONTEXT IrpContext, // OUT PVOID Buffer // ); // // Will raise on failure. // // VOID // UdfLockUserBuffer ( // IN PIRP_CONTEXT IrpContext, // IN ULONG BufferLength // ); // #define UdfMapUserBuffer(IC,UB) { \ *(UB) = ((PVOID) (((IC)->Irp->MdlAddress == NULL) ? \ (IC)->Irp->UserBuffer : \ MmGetSystemAddressForMdlSafe( (IC)->Irp->MdlAddress, NormalPagePriority ))); \ if (NULL == *(UB)) { \ UdfRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES); \ } \ } #define UdfLockUserBuffer(IC,BL,OP) { \ if ((IC)->Irp->MdlAddress == NULL) { \ (VOID) UdfCreateUserMdl( (IC), (BL), TRUE, (OP) ); \ } \ } // // Udf*RawBufferSize and Udf*RawReadSize calculate how big a buffer must be // to do a direct read of a given sector aligned structure (UdfReadSectors) // and how much data the read must recover. Reads must write into whole-page // sized buffers and be in whole-sector units. // // Note that although all descriptors are constrained to fit in one logical // block, it is not always going to be neccesary to read the entire logical // block to get the descriptor. The underlying restriction is the physical // sector. // INLINE ULONG UdfRawBufferSize ( IN PVCB Vcb, IN ULONG StructureSize ) { return (ULONG)ROUND_TO_PAGES( SectorAlign( Vcb, StructureSize )); } INLINE ULONG UdfRawReadSize ( IN PVCB Vcb, IN ULONG StructureSize ) { return SectorAlign( Vcb, StructureSize ); } INLINE ULONG UdfRawBufferSizeN ( IN ULONG SectorSize, IN ULONG StructureSize ) { return (ULONG)ROUND_TO_PAGES( SectorAlignN( SectorSize, StructureSize )); } INLINE ULONG UdfRawReadSizeN ( IN ULONG SectorSize, IN ULONG StructureSize ) { return SectorAlignN( SectorSize, StructureSize ); } // // The following routines are used to read on-disk directory structures, implemented // in DirSup.c // VOID UdfInitializeDirContext ( IN PIRP_CONTEXT IrpContext, IN PDIR_ENUM_CONTEXT DirContext ); VOID UdfCleanupDirContext ( IN PIRP_CONTEXT IrpContext, IN PDIR_ENUM_CONTEXT DirContext ); BOOLEAN UdfLookupInitialDirEntry ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PDIR_ENUM_CONTEXT DirContext, IN PLONGLONG InitialOffset OPTIONAL ); BOOLEAN UdfLookupNextDirEntry ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PDIR_ENUM_CONTEXT DirContext ); VOID UdfUpdateDirNames ( IN PIRP_CONTEXT IrpContext, IN PDIR_ENUM_CONTEXT DirContext, IN BOOLEAN IgnoreCase ); BOOLEAN UdfFindDirEntry ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN BOOLEAN ShortName, IN PDIR_ENUM_CONTEXT DirContext ); // // The following routines are used to manipulate the fscontext fields // of the file object, implemented in FilObSup.c // VOID UdfSetFileObject ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN TYPE_OF_OPEN TypeOfOpen, IN PFCB Fcb OPTIONAL, IN PCCB Ccb OPTIONAL ); TYPE_OF_OPEN UdfDecodeFileObject ( IN PFILE_OBJECT FileObject, OUT PFCB *Fcb, OUT PCCB *Ccb ); TYPE_OF_OPEN UdfFastDecodeFileObject ( IN PFILE_OBJECT FileObject, OUT PFCB *Fcb ); // // FSCTL request support routines. Contained in FsCtrl.c // VOID UdfStoreVolumeDescriptorIfPrevailing ( IN OUT PNSR_VD_GENERIC *StoredVD, IN OUT PNSR_VD_GENERIC NewVD ); // // Name mangling routines. Implemented in Namesup.c // VOID UdfDissectName ( IN PIRP_CONTEXT IrpContext, IN OUT PUNICODE_STRING RemainingName, OUT PUNICODE_STRING FinalName ); BOOLEAN UdfIs8dot3Name ( IN PIRP_CONTEXT IrpContext, IN UNICODE_STRING FileName ); BOOLEAN UdfCandidateShortName ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING Name ); VOID UdfGenerate8dot3Name ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING FileName, OUT PUNICODE_STRING ShortFileName ); VOID UdfConvertCS0DstringToUnicode ( IN PIRP_CONTEXT IrpContext, IN PUCHAR Dstring, IN UCHAR Length OPTIONAL, IN UCHAR FieldLength OPTIONAL, IN OUT PUNICODE_STRING Name ); BOOLEAN UdfCheckLegalCS0Dstring ( PIRP_CONTEXT IrpContext, PUCHAR Dstring, UCHAR Length OPTIONAL, UCHAR FieldLength OPTIONAL, BOOLEAN ReturnOnError ); VOID UdfRenderNameToLegalUnicode ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING Name, IN PUNICODE_STRING RenderedName ); BOOLEAN UdfIsNameInExpression ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING CurrentName, IN PUNICODE_STRING SearchExpression, IN BOOLEAN Wild ); FSRTL_COMPARISON_RESULT UdfFullCompareNames ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING NameA, IN PUNICODE_STRING NameB ); INLINE VOID UdfUpcaseName ( IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING Name, IN OUT PUNICODE_STRING UpcaseName ) /*++ Routine Description: This routine upcases a name with an assertion of success. Arguments: Name - an name to upcase Length - a place to put the upcased name (can be the same as Name) Return Value: None. --*/ { NTSTATUS Status; // // Upcase the string using the correct upcase routine. // Status = RtlUpcaseUnicodeString( UpcaseName, Name, FALSE ); // // This should never fail. // ASSERT( Status == STATUS_SUCCESS ); return; } INLINE USHORT UdfCS0DstringUnicodeSize ( PIRP_CONTEXT IrpContext, PCHAR Dstring, UCHAR Length ) /*++ Routine Description: This routine computes the number of bytes required for the UNICODE representation of a CS0 Dstring (1/7.2.12) Arguments: Dstring - a dstring Length - length of the dstring Return Value: ULONG number of bytes. --*/ { return (16 / *Dstring) * (Length - 1); } INLINE BOOLEAN UdfIsCharacterLegal ( IN WCHAR Character ) /*++ Routine Description: This routine checks that a given UNICODE character is legal. Arguments: Character - a character to check Return Value: BOOLEAN True if a legal character, False otherwise. --*/ { if (Character < 0xff && !FsRtlIsAnsiCharacterLegalHpfs( Character, FALSE )) { return FALSE; } return TRUE; } INLINE BOOLEAN UdfCS0DstringIsLegalFileName( IN PCHAR Dstring, IN ULONG Length ) /*++ Routine Description: This routine inspects a CS0 dstring for illegal characters, and illegal trailing characters. The assumption is made that the string is legal CS0. Arguments: Name - a name to check Return Value: BOOLEAN True if legal characters are found, False otherwise. --*/ { ULONG Step; WCHAR Char; PCHAR Bound = Dstring + Length; // // Determine how big a step we take in the string according to the // "compression" applied. // if (*Dstring == 16) { Step = sizeof( WCHAR ); } else { Step = sizeof( CHAR ); } // // Advance past the compression marker and loop over the string. // for (Dstring++; Dstring < Bound; Dstring += Step) { if ( sizeof(WCHAR) == Step) { // // Perform the endianess swapcopy to convert from UDF bigendian CS0 to our // little endian wide characters. // SwapCopyUchar2( &Char, Dstring ); } else { Char = *Dstring; } if (!UdfIsCharacterLegal( Char )) { DebugTrace(( 0, Dbg, "UdfCS0DstringIsLegalFileName, Char %04x @ %08x\n", (WCHAR) Char, Dstring )); return FALSE; } } // // Now check for illegal trailing characters (' ' or '.') We know that Char // will be the last character in the string. // if ((PERIOD == Char) || (SPACE == Char)) { DebugTrace(( 0, Dbg, "UdfCS0DstringIsLegalFileName, has trailing space or period\n")); return FALSE; } return TRUE; } // // Filesystem control operations. Implemented in Fsctrl.c // NTSTATUS UdfLockVolumeInternal ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject OPTIONAL ); NTSTATUS UdfUnlockVolumeInternal ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject OPTIONAL ); // // Routines to handle the prefix trees attached to directories, used to quickly travel common // bits of the hierarchy. Implemented in PrefxSup.c // PLCB UdfFindPrefix ( IN PIRP_CONTEXT IrpContext, IN OUT PFCB *CurrentFcb, IN OUT PUNICODE_STRING RemainingName, IN BOOLEAN IgnoreCase ); VOID UdfInitializeLcbFromDirContext ( IN PIRP_CONTEXT IrpContext, IN PLCB Lcb, IN PDIR_ENUM_CONTEXT DirContext ); PLCB UdfInsertPrefix ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PUNICODE_STRING Name, IN BOOLEAN ShortNameMatch, IN BOOLEAN IgnoreCase, IN PFCB ParentFcb ); VOID UdfRemovePrefix ( IN PIRP_CONTEXT IrpContext, IN PLCB Lcb ); // // Synchronization routines. Implemented in Resrcsup.c // // The following routines/macros are used to synchronize the in-memory structures. // // Routine/Macro Synchronizes Subsequent // // UdfAcquireUdfData Volume Mounts/Dismounts,Vcb Queue UdfReleaseUdfData // UdfAcquireVcbExclusive Vcb for open/close UdfReleaseVcb // UdfAcquireVcbShared Vcb for open/close UdfReleaseVcb // UdfAcquireAllFiles Locks out operations to all files UdfReleaseAllFiles // UdfAcquireFileExclusive Locks out file operations UdfReleaseFile // UdfAcquireFileShared Files for file operations UdfReleaseFile // UdfAcquireFcbExclusive Fcb for open/close UdfReleaseFcb // UdfAcquireFcbShared Fcb for open/close UdfReleaseFcb // UdfLockUdfData Fields in UdfData UdfUnlockUdfData // UdfLockVcb Vcb fields, FcbReference, FcbTable UdfUnlockVcb // UdfLockFcb Fcb fields, prefix table, Mcb UdfUnlockFcb // typedef enum _TYPE_OF_ACQUIRE { AcquireExclusive, AcquireShared, AcquireSharedStarveExclusive } TYPE_OF_ACQUIRE, *PTYPE_OF_ACQUIRE; BOOLEAN UdfAcquireResource ( IN PIRP_CONTEXT IrpContext, IN PERESOURCE Resource, IN BOOLEAN IgnoreWait, IN TYPE_OF_ACQUIRE Type ); // // BOOLEAN // UdfAcquireUdfData ( // IN PIRP_CONTEXT IrpContext // ); // // VOID // UdfReleaseUdfData ( // IN PIRP_CONTEXT IrpContext // ); // // BOOLEAN // UdfAcquireVcbExclusive ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb, // IN BOOLEAN IgnoreWait // ); // // BOOLEAN // UdfAcquireVcbShared ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb, // IN BOOLEAN IgnoreWait // ); // // VOID // UdfReleaseVcb ( // IN PIRP_CONTEXT IrpContext, // IN PVCB Vcb // ); // // VOID // UdfAcquireAllFiles ( // IN PIRP_CONTEXT, // IN PVCB Vcb // ); // // VOID // UdfReleaseAllFiles ( // IN PIRP_CONTEXT, // IN PVCB Vcb // ); // // VOID // UdfAcquireFileExclusive ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb, // ); // // VOID // UdfAcquireFileShared ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // // VOID // UdfReleaseFile ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // // BOOLEAN // UdfAcquireFcbExclusive ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb, // IN BOOLEAN IgnoreWait // ); // // BOOLEAN // UdfAcquireFcbShared ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb, // IN BOOLEAN IgnoreWait // ); // // BOOLEAN // UdfReleaseFcb ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // // VOID // UdfLockUdfData ( // ); // // VOID // UdfUnlockUdfData ( // ); // // VOID // UdfLockVcb ( // IN PIRP_CONTEXT IrpContext // ); // // VOID // UdfUnlockVcb ( // IN PIRP_CONTEXT IrpContext // ); // // VOID // UdfLockFcb ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // // VOID // UdfUnlockFcb ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // #define UdfAcquireUdfData(IC) \ ExAcquireResourceExclusiveLite( &UdfData.DataResource, TRUE ) #define UdfReleaseUdfData(IC) \ ExReleaseResourceLite( &UdfData.DataResource ) #define UdfAcquireVcbExclusive(IC,V,I) \ UdfAcquireResource( (IC), &(V)->VcbResource, (I), AcquireExclusive ) #define UdfAcquireVcbShared(IC,V,I) \ UdfAcquireResource( (IC), &(V)->VcbResource, (I), AcquireShared ) #define UdfReleaseVcb(IC,V) \ ExReleaseResourceLite( &(V)->VcbResource ) #define UdfAcquireAllFiles(IC,V) \ UdfAcquireResource( (IC), &(V)->FileResource, FALSE, AcquireExclusive ) #define UdfReleaseAllFiles(IC,V) \ ExReleaseResourceLite( &(V)->FileResource ) #define UdfAcquireFileExclusive(IC,F) \ UdfAcquireResource( (IC), (F)->Resource, FALSE, AcquireExclusive ) #define UdfAcquireFileShared(IC,F) \ UdfAcquireResource( (IC), (F)->Resource, FALSE, AcquireShared ) #define UdfAcquireFileSharedStarveExclusive(IC,F) \ UdfAcquireResource( (IC), (F)->Resource, FALSE, AcquireSharedStarveExclusive ) #define UdfReleaseFile(IC,F) \ ExReleaseResourceLite( (F)->Resource ) #define UdfAcquireVmcbForCcMap(IC,V) \ UdfAcquireResource( (IC), &(V)->VmcbMappingResource, FALSE, AcquireShared) #define UdfAcquireVmcbForCcPurge(IC,V) \ UdfAcquireResource( (IC), &(V)->VmcbMappingResource, FALSE, AcquireExclusive) #define UdfReleaseVmcb( IC, V) \ ExReleaseResourceLite( &(V)->VmcbMappingResource) #define UdfAcquireFcbExclusive(IC,F,I) \ UdfAcquireResource( (IC), &(F)->FcbNonpaged->FcbResource, (I), AcquireExclusive ) #define UdfAcquireFcbShared(IC,F,I) \ UdfAcquireResource( (IC), &(F)->FcbNonpaged->FcbResource, (I), AcquireShared ) #define UdfReleaseFcb(IC,F) \ ExReleaseResourceLite( &(F)->FcbNonpaged->FcbResource ) #define UdfLockUdfData() \ ExAcquireFastMutex( &UdfData.UdfDataMutex ); \ UdfData.UdfDataLockThread = PsGetCurrentThread() #define UdfUnlockUdfData() \ UdfData.UdfDataLockThread = NULL; \ ExReleaseFastMutex( &UdfData.UdfDataMutex ) #define UdfLockVcb(IC,V) \ ASSERT(KeAreApcsDisabled()); \ ExAcquireFastMutexUnsafe( &(V)->VcbMutex ); \ (V)->VcbLockThread = PsGetCurrentThread() #define UdfUnlockVcb(IC,V) \ (V)->VcbLockThread = NULL; \ ExReleaseFastMutexUnsafe( &(V)->VcbMutex ) #define UdfLockFcb(IC,F) { \ PVOID _CurrentThread = PsGetCurrentThread(); \ if (_CurrentThread != (F)->FcbLockThread) { \ ASSERT(KeAreApcsDisabled()); \ ExAcquireFastMutexUnsafe( &(F)->FcbNonpaged->FcbMutex ); \ ASSERT( (F)->FcbLockCount == 0 ); \ (F)->FcbLockThread = _CurrentThread; \ } \ (F)->FcbLockCount += 1; \ } #define UdfUnlockFcb(IC,F) { \ ASSERT( PsGetCurrentThread() == (F)->FcbLockThread); \ (F)->FcbLockCount -= 1; \ if ((F)->FcbLockCount == 0) { \ (F)->FcbLockThread = NULL; \ ExReleaseFastMutexUnsafe( &(F)->FcbNonpaged->FcbMutex ); \ } \ } BOOLEAN UdfNoopAcquire ( IN PVOID Fcb, IN BOOLEAN Wait ); VOID UdfNoopRelease ( IN PVOID Fcb ); BOOLEAN UdfAcquireForCache ( IN PFCB Fcb, IN BOOLEAN Wait ); VOID UdfReleaseFromCache ( IN PFCB Fcb ); VOID UdfAcquireForCreateSection ( IN PFILE_OBJECT FileObject ); VOID UdfReleaseForCreateSection ( IN PFILE_OBJECT FileObject ); // // Structure support routines, implemented in StrucSup.c // // These routines perform in-memory structure manipulations. They do *not* operate // on disk structures. // // // Encapsulate manipulation of the Vcb condition for tracing purposes. // #ifndef UDF_SANITY #define UdfSetVcbCondition( V, C) (V)->VcbCondition = (C) #define UdfSetMediaChangeCount( V, C) (V)->MediaChangeCount = (C) #else #define UdfSetVcbCondition( V, C) { \ DebugTrace(( 0, UDFS_DEBUG_LEVEL_VERFYSUP, "VcbCondition %p transitioning %d -> %d (%s : %d)\n", \ (V), (V)->VcbCondition, (C), __FILE__, __LINE__)); \ (V)->VcbCondition = (C); \ } #define UdfSetMediaChangeCount( V, C) { \ DebugTrace(( 0, UDFS_DEBUG_LEVEL_VERFYSUP, "Vcb MCT %p transitioning %d -> %d (%s : %d)\n", \ (V), (V)->MediaChangeCount, (C), __FILE__, __LINE__)); \ (V)->MediaChangeCount = (C); \ } #endif BOOLEAN UdfInitializeVcb ( IN PIRP_CONTEXT IrpContext, IN OUT PVCB Vcb, IN PDEVICE_OBJECT TargetDeviceObject, IN PVPB Vpb, IN PDISK_GEOMETRY DiskGeometry, IN ULONG MediaChangeCount ); VOID UdfUpdateVcbPhase0 ( IN PIRP_CONTEXT IrpContext, IN OUT PVCB Vcb ); VOID UdfUpdateVcbPhase1 ( IN PIRP_CONTEXT IrpContext, IN OUT PVCB Vcb, IN PNSR_FSD Fsd ); VOID UdfDeleteVcb ( IN PIRP_CONTEXT IrpContext, IN OUT PVCB Vcb ); PIRP_CONTEXT UdfCreateIrpContext ( IN PIRP Irp, IN BOOLEAN Wait ); VOID UdfCleanupIrpContext ( IN PIRP_CONTEXT IrpContext, IN BOOLEAN Post ); VOID UdfInitializeStackIrpContext ( OUT PIRP_CONTEXT IrpContext, IN PIRP_CONTEXT_LITE IrpContextLite ); // // PIRP_CONTEXT_LITE // UdfCreateIrpContextLite ( // IN PIRP_CONTEXT IrpContext // ); // // VOID // UdfFreeIrpContextLite ( // IN PIRP_CONTEXT_LITE IrpContextLite // ); // #define UdfCreateIrpContextLite(IC) \ ExAllocatePoolWithTag( UdfNonPagedPool, sizeof( IRP_CONTEXT_LITE ), TAG_IRP_CONTEXT_LITE ) #define UdfFreeIrpContextLite(ICL) \ ExFreePool( ICL ) // // PUDF_IO_CONTEXT // UdfAllocateIoContext ( // ); // // VOID // UdfFreeIoContext ( // PUDF_IO_CONTEXT IoContext // ); // #define UdfAllocateIoContext() \ FsRtlAllocatePoolWithTag( UdfNonPagedPool, \ sizeof( UDF_IO_CONTEXT ), \ TAG_IO_CONTEXT ) #define UdfFreeIoContext(IO) ExFreePool( IO ) // // VOID // UdfIncrementCleanupCounts ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // // VOID // UdfDecrementCleanupCounts ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // // VOID // UdfIncrementReferenceCounts ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb, // IN ULONG ReferenceCount // IN ULONG UserReferenceCount // ); // // VOID // UdfDecrementReferenceCounts ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb, // IN ULONG ReferenceCount // IN ULONG UserReferenceCount // ); // // VOID // UdfIncrementFcbReference ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // // VOID // UdfDecrementFcbReference ( // IN PIRP_CONTEXT IrpContext, // IN PFCB Fcb // ); // #define UdfIncrementCleanupCounts(IC,F) { \ ASSERT_LOCKED_VCB( (F)->Vcb ); \ (F)->FcbCleanup += 1; \ (F)->Vcb->VcbCleanup += 1; \ } #define UdfDecrementCleanupCounts(IC,F) { \ ASSERT_LOCKED_VCB( (F)->Vcb ); \ (F)->FcbCleanup -= 1; \ (F)->Vcb->VcbCleanup -= 1; \ } #define UdfIncrementReferenceCounts(IC,F,C,UC) { \ ASSERT_LOCKED_VCB( (F)->Vcb ); \ (F)->FcbReference += (C); \ (F)->FcbUserReference += (UC); \ (F)->Vcb->VcbReference += (C); \ (F)->Vcb->VcbUserReference += (UC); \ } #define UdfDecrementReferenceCounts(IC,F,C,UC) { \ ASSERT_LOCKED_VCB( (F)->Vcb ); \ (F)->FcbReference -= (C); \ (F)->FcbUserReference -= (UC); \ (F)->Vcb->VcbReference -= (C); \ (F)->Vcb->VcbUserReference -= (UC); \ } VOID UdfTeardownStructures ( IN PIRP_CONTEXT IrpContext, IN PFCB StartingFcb, IN BOOLEAN Recursive, OUT PBOOLEAN RemovedStartingFcb ); PFCB UdfLookupFcbTable ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN FILE_ID FileId ); PFCB UdfGetNextFcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PVOID *RestartKey ); PFCB UdfCreateFcb ( IN PIRP_CONTEXT IrpContext, IN FILE_ID FileId, IN NODE_TYPE_CODE NodeTypeCode, OUT PBOOLEAN FcbExisted OPTIONAL ); VOID UdfDeleteFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ); VOID UdfInitializeFcbFromIcbContext ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PICB_SEARCH_CONTEXT IcbContext, IN PFCB ParentFcb OPTIONAL ); PCCB UdfCreateCcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PLCB Lcb OPTIONAL, IN ULONG Flags ); VOID UdfDeleteCcb ( IN PIRP_CONTEXT IrpContext, IN PCCB Ccb ); ULONG UdfFindInParseTable ( IN PPARSE_KEYVALUE ParseTable, IN PCHAR Id, IN ULONG MaxIdLen ); BOOLEAN UdfVerifyDescriptor ( IN PIRP_CONTEXT IrpContext, IN PDESTAG Descriptor, IN USHORT Tag, IN ULONG Size, IN ULONG Lbn, IN BOOLEAN ReturnError ); VOID UdfInitializeIcbContextFromFcb ( IN PIRP_CONTEXT IrpContext, IN PICB_SEARCH_CONTEXT IcbContext, IN PFCB Fcb ); VOID UdfInitializeIcbContext ( IN PIRP_CONTEXT IrpContext, IN PICB_SEARCH_CONTEXT IcbContext, IN PVCB Vcb, IN USHORT IcbType, IN USHORT Partition, IN ULONG Lbn, IN ULONG Length ); INLINE VOID UdfFastInitializeIcbContext ( IN PIRP_CONTEXT IrpContext, IN PICB_SEARCH_CONTEXT IcbContext ) { RtlZeroMemory( IcbContext, sizeof( ICB_SEARCH_CONTEXT )); } VOID UdfLookupActiveIcb ( IN PIRP_CONTEXT IrpContext, IN PICB_SEARCH_CONTEXT IcbContext, IN ULONG IcbExtentLength ); VOID UdfCleanupIcbContext ( IN PIRP_CONTEXT IrpContext, IN PICB_SEARCH_CONTEXT IcbContext ); VOID UdfInitializeAllocations ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PICB_SEARCH_CONTEXT IcbContext, IN BOOLEAN AllowOneGigWorkaround ); VOID UdfUpdateTimestampsFromIcbContext ( IN PIRP_CONTEXT IrpContext, IN PICB_SEARCH_CONTEXT IcbContext, IN PTIMESTAMP_BUNDLE Timestamps ); BOOLEAN UdfCreateFileLock ( IN PIRP_CONTEXT IrpContext OPTIONAL, IN PFCB Fcb, IN BOOLEAN RaiseOnError ); // // The following macro converts from UDF time to NT time. // INLINE VOID UdfConvertUdfTimeToNtTime ( IN PIRP_CONTEXT IrpContext, IN PTIMESTAMP UdfTime, OUT PLARGE_INTEGER NtTime ) { TIME_FIELDS TimeField; TimeField.Year = UdfTime->Year; TimeField.Month = UdfTime->Month; TimeField.Day = UdfTime->Day; TimeField.Hour = UdfTime->Hour; TimeField.Minute = UdfTime->Minute; TimeField.Second = UdfTime->Second; // // This is where it gets hairy. For some unholy reason, ISO 13346 timestamps // carve the right of the decimal point up into three fields of precision // 10-2, 10-4, and 10-6, each ranging from 0-99. Lawdy. // // To make it easier, since they cannot cause a wrap into the next second, // just save it all up and add it in after the conversion. // TimeField.Milliseconds = 0; if (UdfTime->Type <= 1 && ((UdfTime->Zone >= TIMESTAMP_Z_MIN && UdfTime->Zone <= TIMESTAMP_Z_MAX) || UdfTime->Zone == TIMESTAMP_Z_NONE) && RtlTimeFieldsToTime( &TimeField, NtTime )) { // // Now fold in the remaining sub-second "precision". Read as coversions // through the 10-3 units, then into our 10-7 base. (centi->milli->micro, // etc). // NtTime->QuadPart += ((UdfTime->CentiSecond * (10 * 1000)) + (UdfTime->Usec100 * 100) + UdfTime->Usec) * 10; // // Perform TZ normalization if this is a local time with // specified timezone. // if (UdfTime->Type == 1 && UdfTime->Zone != TIMESTAMP_Z_NONE) { NtTime->QuadPart += Int32x32To64( -UdfTime->Zone, (60 * 10 * 1000 * 1000) ); } } else { // // Epoch. Malformed timestamp. // NtTime->QuadPart = 0; } } // // An equivalence test for Entity IDs. // INLINE BOOLEAN UdfEqualEntityId ( IN PREGID RegID, IN PSTRING Id, IN OPTIONAL PSTRING Suffix ) { return (UdfEqualCountedString( Id, RegID->Identifier ) && #ifndef UDF_SUPPORT_NONSTANDARD_ENTITY_STRINGTERM // // Allow disabling of the check that the identifier // seems to be padded with zero. // // Reason: a couple samples that are otherwise useful // padded some identifiers with junk. // ((Id->Length == sizeof(RegID->Identifier) || RegID->Identifier[Id->Length] == '\0') || !DebugTrace(( 0, Dbg, "UdfEqualEntityId, RegID seems to be terminated with junk!\n" ))) && #endif ((Suffix == NULL) || UdfEqualCountedString( Suffix, RegID->Suffix ))); } BOOLEAN UdfDomainIdentifierContained ( IN PREGID RegID, IN PSTRING Domain, IN USHORT RevisionMin, IN USHORT RevisionMax ); // // In like fashion, we define containment for a UDF Identifier RegID. // INLINE BOOLEAN UdfUdfIdentifierContained ( IN PREGID RegID, IN PSTRING Type, IN USHORT RevisionMin, IN USHORT RevisionMax, IN UCHAR OSClass, IN UCHAR OSIdentifier ) { PUDF_SUFFIX_UDF UdfSuffix = (PUDF_SUFFIX_UDF) RegID->Suffix; return ((UdfSuffix->UdfRevision <= RevisionMax && UdfSuffix->UdfRevision >= RevisionMin) && (OSClass == OSCLASS_INVALID || UdfSuffix->OSClass == OSClass) && (OSIdentifier == OSIDENTIFIER_INVALID || UdfSuffix->OSIdentifier == OSIdentifier) && UdfEqualEntityId( RegID, Type, NULL )); } // // Verification support routines. Contained in verfysup.c // BOOLEAN UdfCheckForDismount ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN Force ); BOOLEAN UdfDismountVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); VOID UdfVerifyVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ); BOOLEAN UdfVerifyFcbOperation ( IN PIRP_CONTEXT IrpContext OPTIONAL, IN PFCB Fcb ); // // BOOLEAN // UdfIsRawDevice ( // IN PIRP_CONTEXT IrpContext, // IN NTSTATUS Status // ); // #define UdfIsRawDevice(IC,S) ( \ ((S) == STATUS_DEVICE_NOT_READY) || \ ((S) == STATUS_NO_MEDIA_IN_DEVICE) \ ) // // Volume Mapped Control Blocks routines, implemented in VmcbSup.c // VOID UdfInitializeVmcb ( IN PVMCB Vmcb, IN POOL_TYPE PoolType, IN ULONG MaximumLbn, IN ULONG LbSize ); VOID UdfUninitializeVmcb ( IN PVMCB Vmcb ); VOID UdfResetVmcb ( IN PVMCB Vmcb ); VOID UdfSetMaximumLbnVmcb ( IN PVMCB Vmcb, IN ULONG MaximumLbn ); BOOLEAN UdfVmcbVbnToLbn ( IN PVMCB Vmcb, IN VBN Vbn, OUT PLBN Lbn, OUT PULONG SectorCount OPTIONAL ); BOOLEAN UdfVmcbLbnToVbn ( IN PVMCB Vmcb, IN LBN Lbn, OUT PVBN Vbn, OUT PULONG SectorCount OPTIONAL ); BOOLEAN UdfAddVmcbMapping ( IN PIRP_CONTEXT IrpContext, IN PVMCB Vmcb, IN LBN Lbn, IN ULONG SectorCount, IN BOOLEAN ExactEnd, OUT PVBN Vbn, OUT PULONG AlignedSectorCount ); VOID UdfRemoveVmcbMapping ( IN PVMCB Vmcb, IN LBN Lbn, IN ULONG SectorCount ); // // Routines to verify the correspondance of the underlying media, implemented in // verfysup.c // NTSTATUS UdfPerformVerify ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PDEVICE_OBJECT DeviceToVerify ); // // Some macros for hiding/tracing the device object verify flag. // #ifndef UDF_SANITY #define UdfMarkRealDevForVerify( DO) SetFlag( (DO)->Flags, DO_VERIFY_VOLUME) #define UdfMarkRealDevVerifyOk( DO) ClearFlag( (DO)->Flags, DO_VERIFY_VOLUME) #else #define UdfMarkRealDevForVerify( DO) { \ DebugTrace((0,UDFS_DEBUG_LEVEL_VERFYSUP,"Mark for verify %p (at %s %d)\n", \ (DO), __FILE__, __LINE__)); \ SetFlag( (DO)->Flags, DO_VERIFY_VOLUME); \ } #define UdfMarkRealDevVerifyOk( DO) { \ DebugTrace((0,UDFS_DEBUG_LEVEL_VERFYSUP,"Clear verify %p (at %s %d)\n", \ (DO), __FILE__, __LINE__)); \ ClearFlag( (DO)->Flags, DO_VERIFY_VOLUME); \ } #endif #define UdfRealDevNeedsVerify( DO) BooleanFlagOn( (DO)->Flags, DO_VERIFY_VOLUME) // // Work queue routines for posting and retrieving an Irp, implemented in // workque.c // NTSTATUS UdfFsdPostRequest( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); VOID UdfPrePostIrp ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); VOID UdfOplockComplete ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); // // Charspecs are small containers that specify a CS type and a text // string specifying a version, etc. This is a convenient way of bottling // up equivalence checks of a charspec. // INLINE BOOLEAN UdfEqualCharspec ( IN PCHARSPEC Charspec, IN PSTRING Identifier, IN UCHAR Type ) { return ((Charspec->Type == Type) && UdfEqualCountedString( Identifier, Charspec->Info)); } // // 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 UdfFspDispatch ( // implemented in FspDisp.c IN PIRP_CONTEXT IrpContext ); VOID UdfFspClose ( // 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 UdfCommonCleanup ( // Implemented in Cleanup.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS UdfCommonClose ( // Implemented in Close.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS UdfCommonCreate ( // Implemented in Create.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS // Implemented in DevCtrl.c UdfCommonDevControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS // Implemented in DirCtrl.c UdfCommonDirControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS UdfCommonFsControl ( // Implemented in FsCtrl.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS // Implemented in LockCtrl.c UdfCommonLockControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS // Implemented in Pnp.c UdfCommonPnp ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS // Implemented in FileInfo.c UdfCommonQueryInfo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS // Implemented in VolInfo.c UdfCommonQueryVolInfo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS // Implemented in Read.c UdfCommonRead ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS UdfCommonWrite ( IN PIRP_CONTEXT IrpContext, // write.c IN PIRP Irp ); NTSTATUS // Implemented in FileInfo.c UdfCommonSetInfo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); NTSTATUS UdfHijackIrpAndFlushDevice ( // flush.c IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PDEVICE_OBJECT TargetDeviceObject ); // BOOLEAN // UdfExtendedFEAllowed( // PVCB Vcb // ) // // Decides, based on the NSR revision encountered on the volume, whether or not the // extended FE is legal and expected on this volume #define UdfExtendedFEAllowed( V) (VsdIdentNSR03 == (V)->NsrVersion) // BOOLEAN // UdfMinLegalVATSize( // PVCB Vcb // ) // // Decides based on the NSR revision encountered on the volume #define UdfMinLegalVATSize( V) ((VsdIdentNSR03 == (V)->NsrVersion) ? UDF_CDUDF_MINIMUM_20x_VAT_SIZE : UDF_CDUDF_MINIMUM_150_VAT_SIZE) // BOOLEAN // UdfVATIcbFileTypeExpected( // PVCB Vcb // ) // // Decides, based on the NSR revision encountered on the volume, what value we // expect the FileType field in the VAT Icb to have #define UdfVATIcbFileTypeExpected( V) ((VsdIdentNSR03 == (V)->NsrVersion) ? ICBTAG_FILE_T_VAT : ICBTAG_FILE_T_NOTSPEC) // BOOLEAN // UdfVATHasHeaderRecord( // PVCB Vcb // ) // // Decides, based on the NSR revision encountered on the volume, if the VAT should have // the header (2.00) record, or the 1.5 style trailing regid. #define UdfVATHasHeaderRecord( V) (VsdIdentNSR03 == (V)->NsrVersion) // // Clean up our internal-to-the-header definitions so they do not leak out. // #undef BugCheckFileId #undef Dbg #endif // _UDFPROCS_